heygen-com/hyperframes · error · Error

[build-zip] chrome-headless-shell cache missing at ${baseDir

Error message

[build-zip] chrome-headless-shell cache missing at ${baseDir}. Run
  npx --yes @puppeteer/browsers install chrome-headless-shell@stable --path ${home}/.cache/puppeteer
before --source=chrome-headless-shell.

What it means

When using --source=chrome-headless-shell, the build expects Puppeteer's browser cache at ~/.cache/puppeteer/chrome-headless-shell/. If that directory does not exist, it throws with the exact npx @puppeteer/browsers install command to populate the cache. The build reuses the cache rather than downloading Chrome itself.

Source

Thrown at packages/aws-lambda/scripts/build-zip.ts:448

      `[build-zip] ffprobe-static binary not found under ${ffprobeModule}/bin/linux/. Did postinstall run?`,
    );
  }
  const ffprobeDest = join(binDir, "ffprobe");
  cpSync(ffprobeBinary, ffprobeDest);
  chmodSync(ffprobeDest, 0o755);

  console.log(`[build-zip] staged ffmpeg + ffprobe → bin/`);
}

function stageChromeHeadlessShell(stagingDir: string): void {
  // The fallback path bundles the same chrome-headless-shell binary the
  // K8s deploy uses. The binary is fetched via `@puppeteer/browsers` on
  // first build into the host's `~/.cache/puppeteer/`; the build script
  // re-uses that cache rather than redownloading.
  const home = process.env.HOME ?? "/root";
  const baseDir = join(home, ".cache", "puppeteer", "chrome-headless-shell");
  if (!existsSync(baseDir)) {
    throw new Error(
      `[build-zip] chrome-headless-shell cache missing at ${baseDir}. Run\n` +
        `  npx --yes @puppeteer/browsers install chrome-headless-shell@stable --path ${home}/.cache/puppeteer\n` +
        `before --source=chrome-headless-shell.`,
    );
  }
  // Sort by numeric semver descending. `sort().reverse()` is lexicographic,
  // which silently picks "99.0.0" over "131.0.0" once Chrome ships
  // three-digit majors that aren't strictly width-aligned. `compareSemver`
  // returns negative/zero/positive on (a, b), so descending = `b - a`.
  const versions = readdirSync(baseDir).sort((a, b) => compareSemver(b, a));
  for (const v of versions) {
    const candidate = join(baseDir, v, "chrome-headless-shell-linux64", "chrome-headless-shell");
    if (existsSync(candidate)) {
      const dest = join(stagingDir, "bin", "chrome-headless-shell");
      mkdirSync(dirname(dest), { recursive: true });
      cpSync(candidate, dest);
      chmodSync(dest, 0o755);
      console.log(`[build-zip] staged chrome-headless-shell (${v}) → bin/chrome-headless-shell`);

View on GitHub (pinned to c2996c8626)

Solutions

  1. Run: npx --yes @puppeteer/browsers install chrome-headless-shell@stable --path ~/.cache/puppeteer
  2. Switch to --source=sparticuz which does not need the Puppeteer cache.
  3. In CI, add the install command as a pre-build step and cache the ~/.cache/puppeteer directory.
Defensive patterns

Strategy: validation

Validate before calling

import { existsSync } from "node:fs";
import { join } from "node:path";
const home = process.env.HOME ?? "/root";
const cacheDir = join(home, ".cache", "puppeteer", "chrome-headless-shell");
if (!existsSync(cacheDir)) {
  console.error(`Puppeteer cache missing at ${cacheDir}. Run: npx --yes @puppeteer/browsers install chrome-headless-shell@stable --path ${join(home, ".cache", "puppeteer")}`);
  process.exit(1);
}

Prevention

When it happens

Trigger: Running with --source=chrome-headless-shell without having first run the Puppeteer browsers install command. The cache directory is absent.

Common situations: First build with chrome-headless-shell source on a new machine; CI environment without the Puppeteer cache; HOME environment variable pointing somewhere unexpected so the cache path resolves wrong.

Related errors


AI-assisted analysis of heygen-com/hyperframes@c2996c8626 (2026-08-12). Data as JSON: /api/errors/e1242c1d8e0e7a8c. Report an issue: GitHub.