{"record":{"id":"658dc56baadf11e7","repo":"heygen-com/hyperframes","slug":"could-not-extract-a-frame-from-video-framepath","errorCode":null,"errorMessage":"Could not extract a frame from video: ${framePath}","messagePattern":"Could not extract a frame from video: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/commands/grade-compare.ts","lineNumber":526,"sourceCode":"      const detail = result.stderr.trim() ? `: ${result.stderr.trim()}` : \"\";\n      throw new Error(`ffmpeg could not extract first frame from ${videoPath}${detail}`);\n    }\n    return readFileSync(outPath);\n  } finally {\n    rmSync(tmp, { recursive: true, force: true });\n  }\n}\n\nasync function loadReferenceFrame(framePath: string): Promise<ReferenceFrame> {\n  if (!existsSync(framePath)) {\n    throw new Error(`Reference frame not found: ${framePath}`);\n  }\n\n  const buffer = isVideoPath(framePath)\n    ? await extractVideoFrameToBuffer(framePath)\n    : readFileSync(framePath);\n  if (!buffer) {\n    throw new Error(`Could not extract a frame from video: ${framePath}`);\n  }\n\n  const metadata = await sharp(buffer).metadata();\n  if (!metadata.width || !metadata.height) {\n    throw new Error(`Could not read reference frame dimensions: ${framePath}`);\n  }\n\n  return {\n    buffer,\n    width: metadata.width,\n    height: metadata.height,\n    stagedName: isVideoPath(framePath) ? \"frame.png\" : frameFileNameForPath(framePath),\n  };\n}\n\nasync function captureGradeCompareSheet(\n  projectDir: string,\n  timeoutMs: number,","sourceCodeStart":508,"sourceCodeEnd":544,"githubUrl":"https://github.com/heygen-com/hyperframes/blob/c2996c8626135db5253519359d8a063d3bafad8d/packages/cli/src/commands/grade-compare.ts#L508-L544","documentation":"Thrown by loadReferenceFrame when `--for` is a video path and extractVideoFrameToBuffer returned null. The only null return path in that function is when findFFmpeg() cannot locate an ffmpeg binary — meaning no ffmpeg is available to extract a frame from the supplied video.","triggerScenarios":"Passing `--for video.mp4` on a machine where ffmpeg is not installed or not on PATH. findFFmpeg searches known locations and PATH; if none yields a usable binary, the extractor returns null and this error names the video.","commonSituations":"Fresh CI runner without ffmpeg preinstalled; a slim Docker image; ffmpeg installed but not on PATH; `FFMPEG_BINARY_PATH` not set when ffmpeg lives in a nonstandard location.","solutions":["Install ffmpeg and ensure it's on PATH (`ffmpeg -version` should succeed in the same shell).","If ffmpeg is installed somewhere nonstandard, set the env var HyperFrames' findFFmpeg honors (FFMPEG_BINARY_PATH) to its absolute path.","Alternatively, pre-extract a frame to PNG and pass `--for frame.png` so no ffmpeg is needed at compare time."],"exampleFix":"# before — no ffmpeg on PATH\nhyperframes grade-compare --for clip.mp4 --grades g.json\n# after — install ffmpeg, or extract manually\nffmpeg -i clip.mp4 -frames:v 1 frame.png\nhyperframes grade-compare --for frame.png --grades g.json","handlingStrategy":"validation","validationCode":"// Ensure ffmpeg is available before handing a video to grade-compare\nimport { spawnSync } from \"node:child_process\";\nfunction ffmpegAvailable(): boolean {\n  return spawnSync(\"ffmpeg\", [\"-version\"], { stdio: \"ignore\" }).status === 0;\n}\nif (isVideoPath(frame) && !ffmpegAvailable()) {\n  throw new Error(\"ffmpeg not on PATH; pre-extract a frame or install ffmpeg\");\n}","typeGuard":"function isVideoPath(p: string): boolean {\n  return /\\.(mp4|mov|m4v|webm|mkv|avi|mpeg|mpg|ogv)$/i.test(p);\n}","tryCatchPattern":"try {\n  // run grade-compare on a video\n} catch (err) {\n  if (/Could not extract a frame from video/.test((err as Error).message))) {\n    // install ffmpeg, or pre-extract a PNG and pass that as --for\n  }\n}","preventionTips":["Install ffmpeg in CI/Docker images that run grade-compare on videos.","Set FFMPEG_BINARY_PATH if ffmpeg lives in a nonstandard location.","Default to pre-extracted PNG frames for reproducible CI runs."],"tags":["cli","ffmpeg","video","grade-compare","environment","path"],"backgroundTag":null,"analyzedSha":"c2996c8626135db5253519359d8a063d3bafad8d","analyzedAt":"2026-08-12T22:18:56.877Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}