heygen-com/hyperframes · error · Error

ffmpeg timed out extracting first frame from ${videoPath}

Error message

ffmpeg timed out extracting first frame from ${videoPath}

What it means

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.

Source

Thrown at packages/cli/src/commands/grade-compare.ts:505

    if (!ffmpegPath) return null;
    const args = [
      "-hide_banner",
      "-loglevel",
      "error",
      "-ss",
      "0",
      "-i",
      videoPath,
      "-frames:v",
      "1",
      "-q:v",
      "2",
      "-y",
      outPath,
    ];
    const result = await runFfmpegOnce(ffmpegPath, args, FFMPEG_EXTRACT_TIMEOUT_MS);
    if (result.timedOut) {
      throw new Error(`ffmpeg timed out extracting first frame from ${videoPath}`);
    }
    if (result.code !== 0 || !existsSync(outPath)) {
      const detail = result.stderr.trim() ? `: ${result.stderr.trim()}` : "";
      throw new Error(`ffmpeg could not extract first frame from ${videoPath}${detail}`);
    }
    return readFileSync(outPath);
  } finally {
    rmSync(tmp, { recursive: true, force: true });
  }
}

async function loadReferenceFrame(framePath: string): Promise<ReferenceFrame> {
  if (!existsSync(framePath)) {
    throw new Error(`Reference frame not found: ${framePath}`);
  }

  const buffer = isVideoPath(framePath)
    ? await extractVideoFrameToBuffer(framePath)

View on GitHub (pinned to c2996c8626)

Solutions

  1. 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.
  2. Verify the video plays and isn't corrupt with `ffprobe video.mp4`.
  3. If the video is large, trim or re-encode it to something ffmpeg can seek quickly before running grade-compare.
  4. Retry on faster local storage if the file is on a slow/network mount.

Example fix

# before — hand ffmpeg the whole video
hyperframes grade-compare --for clip.mp4 --grades g.json
# after — pre-extract the frame
ffmpeg -i clip.mp4 -ss 0 -frames:v 1 -q:v 2 frame.png
hyperframes grade-compare --for frame.png --grades g.json
Defensive patterns

Strategy: fallback

Validate before calling

// Pre-extract a frame so the CLI never shells out to ffmpeg
import { spawnSync } from "node:child_process";
function ensureFrame(videoPath: string): string {
  const out = videoPath.replace(/\.[^.]+$/, "") + ".frame.png";
  const r = spawnSync("ffmpeg", ["-i", videoPath, "-frames:v", "1", "-q:v", "2", "-y", out]);
  if (r.status !== 0) throw new Error("ffmpeg pre-extract failed");
  return out;
}

Try / catch

try {
  // pass video to grade-compare
} catch (err) {
  if (/timed out extracting first frame/.test((err as Error).message))) {
    // pre-extract and pass the PNG instead
  }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Related errors


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