Skip to content

fix(producer): fall back to a temp dir when the font cache is unwritable - #3425

Open
miguel-heygen wants to merge 1 commit into
mainfrom
fix/font-cache-best-effort
Open

fix(producer): fall back to a temp dir when the font cache is unwritable#3425
miguel-heygen wants to merge 1 commit into
mainfrom
fix/font-cache-best-effort

Conversation

@miguel-heygen

Copy link
Copy Markdown
Collaborator

What

An unwritable font cache directory no longer aborts the render. It falls back to a temp
directory and warns once.

Closes #3412.

Why

The font cache holds Google Fonts downloads between runs. It is an optimisation — the
bytes are still fetchable without it — but failing to create it was fatal, because
fontCacheDir called mkdirSync unguarded during compile and the throw propagated out of
the render.

A first-time user on 0.8.8 lost their very first render to it:

EPERM: operation not permitted, mkdir '<home>/.cache/hyperframes/fonts/inter'

Two things made it worse than the bug. The CLI's remediation was Try --docker for containerized rendering, which does not address an unwritable host directory. And
HYPERFRAMES_FONT_CACHE_DIR — which would have rescued them — appears in no user-facing
guide page.

How

fontCacheDir now catches the failure and falls back to one temp root per process, the same
shape the Lambda cache root a few lines above already uses:

fallbackFontCacheRoot ??= mkdtempSync(join(tmpdir(), "hyperframes-fonts-"));

A run still de-duplicates its own downloads; it just cannot reuse them next time. The
one-time warning names HYPERFRAMES_FONT_CACHE_DIR, so the escape hatch is discoverable at
the moment it is needed.

Test plan

End to end, before and after. Pointing HYPERFRAMES_FONT_CACHE_DIR at a path under a
chmod 500 parent, rendering a composition that requests Inter.

Before:

✗  Render failed
   EACCES: permission denied, mkdir '.../rocache/nested'
   Try --docker for containerized rendering

After:

[WARN] [Compiler] Font cache is not writable (EACCES: permission denied, mkdir '...').
       Caching to a temporary directory for this run instead; fonts will be re-downloaded
       next time. Set HYPERFRAMES_FONT_CACHE_DIR to a writable path to keep them.
  █████████████████████████  100%  Render complete

New regression test deterministicFonts-unwritableCache.test.ts drives
injectDeterministicFontFaces with the cache root under a read-only parent. Verified it
fails on the unfixed code rather than assuming:

EACCES: permission denied, mkdir '/var/folders/.../hf-font-locked-nSYU6R/nested'
(fail) unwritable font cache > still resolves fonts instead of aborting the render

All deterministicFonts suites green: 61 pass across 8 files.

Not covered

  • The misleading Try --docker remediation is unchanged. It is emitted generically for
    render failures, so fixing it is a separate change about how that hint is chosen.
  • HYPERFRAMES_FONT_CACHE_DIR is still absent from the docs site. Now surfaced in the
    warning, but a real docs page would be better.

The font cache holds Google Fonts downloads between runs. It is an
optimisation — the bytes are still fetchable without it — but failing to create
it was fatal, because `fontCacheDir` called `mkdirSync` unguarded during
compile and the throw propagated straight out of the render.

A first-time user on 0.8.8 lost their very first render to it:

  EPERM: operation not permitted, mkdir '<home>/.cache/hyperframes/fonts/inter'

and the remediation the CLI offered was "Try --docker for containerized
rendering", which does not address an unwritable host directory.

Fall back to one temp root per process — the same shape the Lambda cache root
in this file already uses — and warn once with the env var that makes the
fallback unnecessary. A run still de-duplicates its own downloads; it just
cannot reuse them next time.

Reproduced end to end before and after: pointing HYPERFRAMES_FONT_CACHE_DIR at
a path under a chmod 500 parent used to print "Render failed / EACCES" and now
renders, emitting a single actionable warning.

Closes #3412.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unwritable font cache directory aborts the render instead of degrading

1 participant