{"record":{"id":"786ba914130331c2","repo":"heygen-com/hyperframes","slug":"build-zip-zip-exited-with-status-result-status","errorCode":null,"errorMessage":"[build-zip] zip exited with status ${result.status}","messagePattern":"\\[build-zip\\] zip exited with status (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/aws-lambda/scripts/build-zip.ts","lineNumber":498,"sourceCode":"function compareSemver(a: string, b: string): number {\n  const partsA = a.split(\".\").map((s) => Number.parseInt(s, 10));\n  const partsB = b.split(\".\").map((s) => Number.parseInt(s, 10));\n  const len = Math.max(partsA.length, partsB.length);\n  for (let i = 0; i < len; i++) {\n    const ai = partsA[i] ?? 0;\n    const bi = partsB[i] ?? 0;\n    if (Number.isNaN(ai) && Number.isNaN(bi)) continue;\n    if (Number.isNaN(ai)) return -1;\n    if (Number.isNaN(bi)) return 1;\n    if (ai !== bi) return ai - bi;\n  }\n  return 0;\n}\n\nfunction zipDirectory(sourceDir: string, zipPath: string): void {\n  const result = spawnSync(\"zip\", [\"-rq\", zipPath, \".\"], { cwd: sourceDir, stdio: \"inherit\" });\n  if (result.status !== 0) {\n    throw new Error(`[build-zip] zip exited with status ${result.status}`);\n  }\n}\n\nfunction directorySizeBytes(dir: string): number {\n  // Use spawnSync (no shell) instead of execSync so `dir` is passed as\n  // an argv element rather than interpolated into a shell command —\n  // CodeQL's `js/shell-command-injected-from-environment` rule fires\n  // on the latter even with JSON-quoting. `du -sb` is Linux-only;\n  // build-zip is CI-side where Linux coreutils is present.\n  const result = spawnSync(\"du\", [\"-sb\", dir], { encoding: \"utf-8\" });\n  if (result.status === 0 && result.stdout) {\n    const bytes = Number.parseInt(result.stdout.split(/\\s+/)[0] ?? \"0\", 10);\n    if (!Number.isNaN(bytes)) return bytes;\n  }\n  return walkSize(dir);\n}\n\nfunction walkSize(dir: string): number {","sourceCodeStart":480,"sourceCodeEnd":516,"githubUrl":"https://github.com/heygen-com/hyperframes/blob/c2996c8626135db5253519359d8a063d3bafad8d/packages/aws-lambda/scripts/build-zip.ts#L480-L516","documentation":"zipDirectory runs the system 'zip -rq <zipPath> .' inside the staging directory. If the zip utility exits non-zero, the build throws. This means zip is not installed, ran out of disk space, or encountered a filesystem error such as permissions or path-length issues.","triggerScenarios":"The zip utility is not available on the build host; disk is full; permission errors on files in staging; a path too long for zip to handle.","commonSituations":"Minimal Docker image (e.g., node:20-alpine or node:20-slim) without zip installed; CI runner out of disk space.","solutions":["Install zip: apt-get install -y zip (Debian/Ubuntu) or apk add zip (Alpine).","Check available disk space: df -h.","Check permissions on the staging directory and its contents."],"exampleFix":"// before (Dockerfile)\nFROM node:20-alpine\nRUN npm install\n\n// after\nFROM node:20-alpine\nRUN apk add --no-cache zip && npm install","handlingStrategy":"validation","validationCode":"import { spawnSync } from \"node:child_process\";\nconst check = spawnSync(\"which\", [\"zip\"], { encoding: \"utf-8\" });\nif (check.status !== 0) {\n  console.error(\"'zip' is not installed. Install it: apt-get install -y zip (or apk add zip on Alpine).\");\n  process.exit(1);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Include zip in the build Docker image (apk add zip or apt-get install -y zip).","Check disk space before building.","Verify staging directory permissions before zipping."],"tags":["zip","build","system-dependency"],"backgroundTag":null,"analyzedSha":"c2996c8626135db5253519359d8a063d3bafad8d","analyzedAt":"2026-08-12T22:18:56.877Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}