heygen-com/hyperframes · error · Error
[build-zip] unzipped bundle ${formatBytes(unzippedBytes)} ex
Error message
[build-zip] unzipped bundle ${formatBytes(unzippedBytes)} exceeds limit ${formatBytes(opts.maxUnzippedBytes)} (Lambda ZIP ceiling: 250 MiB unzipped). Switch --source to the lighter option, or move Chrome to a Lambda Layer. What it means
AWS Lambda enforces a 250 MiB unzipped deployment package ceiling. The build computes the staging directory size via 'du -sb' before zipping and throws if it exceeds opts.maxUnzippedBytes (default 250 MiB). This prevents shipping a bundle that Lambda will reject at deploy time with a less clear error.
Source
Thrown at packages/aws-lambda/scripts/build-zip.ts:148
stageFfmpeg(stagingDir);
// 3b. Stage the hyperframe runtime manifest + IIFE as siblings of
// handler.mjs. The producer's `hyperframeRuntimeLoader` checks
// SIBLING_MANIFEST_PATH first, so dropping the manifest alongside
// the bundled handler at /var/task/hyperframe.manifest.json lets
// renderChunk find it without needing PRODUCER_HYPERFRAME_MANIFEST_PATH.
stageHyperframeRuntime(stagingDir);
// 4. If we're on the chrome-headless-shell fallback, stage that binary.
if (opts.source === "chrome-headless-shell") {
stageChromeHeadlessShell(stagingDir);
}
// 5. Compute the unzipped size BEFORE zipping so we fail loud when over budget.
const unzippedBytes = directorySizeBytes(stagingDir);
console.log(`[build-zip] unzipped staging size: ${formatBytes(unzippedBytes)}`);
if (unzippedBytes > opts.maxUnzippedBytes) {
throw new Error(
`[build-zip] unzipped bundle ${formatBytes(unzippedBytes)} exceeds limit ${formatBytes(
opts.maxUnzippedBytes,
)} (Lambda ZIP ceiling: 250 MiB unzipped). ` +
`Switch --source to the lighter option, or move Chrome to a Lambda Layer.`,
);
}
// 6. Build the ZIP.
const zipPath = join(distDir, "handler.zip");
zipDirectory(stagingDir, zipPath);
const zippedBytes = statSync(zipPath).size;
console.log(`[build-zip] zip size: ${formatBytes(zippedBytes)} → ${zipPath}`);
if (zippedBytes > opts.maxZippedBytes) {
throw new Error(
`[build-zip] zip ${formatBytes(zippedBytes)} exceeds ZIP size limit ${formatBytes(
opts.maxZippedBytes,
)}.`,
);View on GitHub (pinned to c2996c8626)
Solutions
- Switch to --source=sparticuz (the lighter Chromium provider).
- Move Chrome and/or ffmpeg to a Lambda Layer instead of bundling in the ZIP.
- Raise the limit with --max-unzipped=<bytes> only if you are confident the Lambda unzipped ceiling does not apply (e.g., layers).
Example fix
// before tsx build-zip.ts --source=chrome-headless-shell // after tsx build-zip.ts --source=sparticuz
Defensive patterns
Strategy: validation
Validate before calling
import { spawnSync } from "node:child_process";
const stagingSize = parseInt(
spawnSync("du", ["-sb", stagingDir], { encoding: "utf-8" }).stdout.split(/\s+/)[0] ?? "0",
10,
);
const LIMIT = 250 * 1024 * 1024;
if (stagingSize > LIMIT) {
console.error(`Unzipped size ${stagingSize} exceeds ${LIMIT}. Switch to --source=sparticuz or use a Lambda Layer.`);
process.exit(1);
} Prevention
- Default to --source=sparticuz to stay under the unzipped ceiling.
- Move Chrome and ffmpeg to a Lambda Layer for production deployments.
- Monitor staging size in CI as a regression signal.
When it happens
Trigger: The staged directory (node_modules + ffmpeg + ffprobe + hyperframe runtime + optional Chrome binary) exceeds the unzipped byte limit. Most common when using --source=chrome-headless-shell, which adds ~150+ MiB of Chrome on top of ffmpeg and node_modules.
Common situations: Building with chrome-headless-shell source on a host where Chromium is large; dependency bloat from newly added packages; using the heavier source when sparticuz would suffice.
Related errors
- [build-zip] zip ${formatBytes(zippedBytes)} exceeds ZIP size
- --source must be 'sparticuz' or 'chrome-headless-shell' (got
- [build-zip] ${label} at ${path} is not a Linux x86-64 ELF ex
- [validateConfig] config: Step Functions execution input is $
- Unknown flag: ${arg}
AI-assisted analysis of heygen-com/hyperframes@c2996c8626 (2026-08-12).
Data as JSON: /api/errors/d6a0582d7df0e88f.
Report an issue: GitHub.