Skip to content

Unwritable font cache directory aborts the render instead of degrading #3412

Description

@miguel-heygen

Describe the bug

A render fails outright when the font cache directory cannot be created. The cache is an
optimisation — it stores Google Fonts downloads between runs — but failing to create it is
fatal, so a first render dies with a raw mkdir error.

Reported from the field on 0.8.8, on a first-ever render:

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

The remediation the CLI offers for this failure is Try --docker for containerized rendering, which does not address an unwritable cache root.

Steps to reproduce

Platform-independent — any unwritable cache root reproduces it:

mkdir -p /tmp/rocache && chmod 500 /tmp/rocache
# a composition using any Google font (e.g. Inter)
HYPERFRAMES_FONT_CACHE_DIR=/tmp/rocache/nested npx hyperframes render --output renders/o.mp4

Actual behavior

✗  Render failed

   EACCES: permission denied, mkdir '/tmp/rocache/nested'
   Try --docker for containerized rendering

Same shape as the field report (EACCES vs EPERM are the same class here: the cache root
is not writable).

Expected behavior

An unwritable cache should degrade, not abort. The font can still be fetched per-run, or
cached to a temp directory. The render only needs the font bytes; where they are stored
between runs is an optimisation detail.

Root cause

packages/producer/src/services/deterministicFonts.ts:612:

function fontCacheDir(slug: string): string {
  const dir = join(resolveFontCacheRoot(), slug);
  if (!existsSync(dir)) {
    mkdirSync(dir, { recursive: true });
  }
  return dir;
}

The mkdirSync is unguarded, and this runs during compile, so the throw propagates and
fails the render.

Notes

  • HYPERFRAMES_FONT_CACHE_DIR exists and would let an affected user redirect the cache, but
    it appears in no user-facing guide or reference page (grep -rlI HYPERFRAMES_FONT_CACHE_DIR docs matches only changelog / weekly-update / plan files). A
    user hitting this has no documented way out.
  • Worth fixing the remediation hint at the same time: suggesting Docker for a permissions
    error on the host cache sends people the wrong way.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions