{"record":{"id":"2472085fb1f155fb","repo":"heygen-com/hyperframes","slug":"ffmpeg-timed-out-extracting-first-frame-from-vid","errorCode":null,"errorMessage":"ffmpeg timed out extracting first frame from ${videoPath}","messagePattern":"ffmpeg timed out extracting first frame from (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/commands/grade-compare.ts","lineNumber":505,"sourceCode":"    if (!ffmpegPath) return null;\n    const args = [\n      \"-hide_banner\",\n      \"-loglevel\",\n      \"error\",\n      \"-ss\",\n      \"0\",\n      \"-i\",\n      videoPath,\n      \"-frames:v\",\n      \"1\",\n      \"-q:v\",\n      \"2\",\n      \"-y\",\n      outPath,\n    ];\n    const result = await runFfmpegOnce(ffmpegPath, args, FFMPEG_EXTRACT_TIMEOUT_MS);\n    if (result.timedOut) {\n      throw new Error(`ffmpeg timed out extracting first frame from ${videoPath}`);\n    }\n    if (result.code !== 0 || !existsSync(outPath)) {\n      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)","sourceCodeStart":487,"sourceCodeEnd":523,"githubUrl":"https://github.com/heygen-com/hyperframes/blob/c2996c8626135db5253519359d8a063d3bafad8d/packages/cli/src/commands/grade-compare.ts#L487-L523","documentation":"Thrown by extractVideoFrameToBuffer when the ffmpeg subprocess did not finish within FFMPEG_EXTRACT_TIMEOUT_MS (30 seconds) while grabbing one frame at t=0 from a video reference. runFfmpegOnce reports timedOut=true, so the command fails fast instead of hanging the whole render on a stuck ffmpeg.","triggerScenarios":"Passing `--for video.mp4` (or .mov/.mkv/.webm/etc.) where ffmpeg hangs — e.g. a corrupt container, a very large remote-ish file, slow disk, or a ffmpeg build stuck on a particular codec. The 30s cap is hit before the first frame is written.","commonSituations":"Corrupt or partially downloaded video; an unusual codec that ffmpeg decodes slowly on a cold cache; resource-constrained CI runner; a network-mounted filesystem with high latency.","solutions":["Pre-extract a frame yourself (`ffmpeg -i video.mp4 -frames:v 1 frame.png`) and pass `--for frame.png` to bypass the in-CLI extraction entirely.","Verify the video plays and isn't corrupt with `ffprobe video.mp4`.","If the video is large, trim or re-encode it to something ffmpeg can seek quickly before running grade-compare.","Retry on faster local storage if the file is on a slow/network mount."],"exampleFix":"# before — hand ffmpeg the whole video\nhyperframes grade-compare --for clip.mp4 --grades g.json\n# after — pre-extract the frame\nffmpeg -i clip.mp4 -ss 0 -frames:v 1 -q:v 2 frame.png\nhyperframes grade-compare --for frame.png --grades g.json","handlingStrategy":"fallback","validationCode":"// Pre-extract a frame so the CLI never shells out to ffmpeg\nimport { spawnSync } from \"node:child_process\";\nfunction ensureFrame(videoPath: string): string {\n  const out = videoPath.replace(/\\.[^.]+$/, \"\") + \".frame.png\";\n  const r = spawnSync(\"ffmpeg\", [\"-i\", videoPath, \"-frames:v\", \"1\", \"-q:v\", \"2\", \"-y\", out]);\n  if (r.status !== 0) throw new Error(\"ffmpeg pre-extract failed\");\n  return out;\n}","typeGuard":null,"tryCatchPattern":"try {\n  // pass video to grade-compare\n} catch (err) {\n  if (/timed out extracting first frame/.test((err as Error).message))) {\n    // pre-extract and pass the PNG instead\n  }\n}","preventionTips":["Always pre-extract a frame for large/long videos instead of handing the whole file to grade-compare.","Verify videos with ffprobe before grading.","Keep reference videos short or seekable to stay under the 30s cap."],"tags":["cli","ffmpeg","video","timeout","grade-compare"],"backgroundTag":null,"analyzedSha":"c2996c8626135db5253519359d8a063d3bafad8d","analyzedAt":"2026-08-12T22:18:56.877Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}