heygen-com/hyperframes · error · Error

--source must be 'sparticuz' or 'chrome-headless-shell' (got

Error message

--source must be 'sparticuz' or 'chrome-headless-shell' (got ${v})

What it means

The --source flag selects which Chromium provider gets bundled into the Lambda ZIP. It accepts exactly two values: 'sparticuz' (the lightweight @sparticuz/chromium Lambda-optimized build) and 'chrome-headless-shell' (the heavier Puppeteer fallback). The parseArgs function rejects any other value at argument-parsing time, before any build work begins.

Source

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

  // MiB) + bundled Node deps put us close to the ceiling. Chrome itself
  // decompresses into Lambda's `/tmp` at cold start, which has its own
  // 10 GiB budget, so the unzipped /var/task footprint above is what
  // actually competes with Lambda's 250 MiB limit.
  maxUnzippedBytes: 248 * 1024 * 1024,
  // Lambda's only zipped-size cap is for direct console/CLI uploads (50
  // MiB); S3-deployed functions are bounded by the unzipped ceiling. We
  // gate at 150 MiB to flag a sudden bundle-size regression without
  // false-failing on the natural ~100 MiB sparticuz + ffmpeg payload.
  maxZippedBytes: 150 * 1024 * 1024,
};

function parseArgs(argv: string[]): BuildOptions {
  const opts = { ...DEFAULT_OPTIONS };
  for (const arg of argv.slice(2)) {
    if (arg.startsWith("--source=")) {
      const v = arg.slice("--source=".length);
      if (v !== "sparticuz" && v !== "chrome-headless-shell") {
        throw new Error(`--source must be 'sparticuz' or 'chrome-headless-shell' (got ${v})`);
      }
      opts.source = v;
    } else if (arg.startsWith("--max-unzipped=")) {
      opts.maxUnzippedBytes = Number.parseInt(arg.slice("--max-unzipped=".length), 10);
    } else if (arg.startsWith("--max-zipped=")) {
      opts.maxZippedBytes = Number.parseInt(arg.slice("--max-zipped=".length), 10);
    } else if (arg === "--help") {
      console.log(
        "Usage: tsx build-zip.ts [--source=sparticuz|chrome-headless-shell]\n" +
          "                       [--max-unzipped=<bytes>] [--max-zipped=<bytes>]",
      );
      process.exit(0);
    } else {
      throw new Error(`Unknown flag: ${arg}`);
    }
  }
  return opts;
}

View on GitHub (pinned to c2996c8626)

Solutions

  1. Use exactly --source=sparticuz or --source=chrome-headless-shell.
  2. Run 'tsx build-zip.ts --help' to see the accepted values.
  3. Omit the flag entirely to use the default source (sparticuz).

Example fix

// before
tsx build-zip.ts --source=chrome

// after
tsx build-zip.ts --source=chrome-headless-shell
Defensive patterns

Strategy: validation

Validate before calling

const VALID_SOURCES = ["sparticuz", "chrome-headless-shell"] as const;
const source = process.argv.find((a) => a.startsWith("--source="))?.slice("--source=".length);
if (source !== undefined && !VALID_SOURCES.includes(source as any)) {
  console.error(`Invalid --source. Valid: ${VALID_SOURCES.join(", ")}`);
  process.exit(1);
}

Type guard

function isValidSource(v: string): v is "sparticuz" | "chrome-headless-shell" {
  return v === "sparticuz" || v === "chrome-headless-shell";
}

Prevention

When it happens

Trigger: Running build-zip.ts with --source set to anything other than 'sparticuz' or 'chrome-headless-shell' — e.g., --source=chrome, --source=chromium, --source=puppeteer, or a typo like --source=spartucus.

Common situations: Copy-pasting an outdated CI command; typos in GitHub Actions YAML; muscle memory from a different tool's flag names; trying a shorthand that was never supported.

Related errors


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