heygen-com/hyperframes · error · Error

ffmpeg could not extract first frame from ${videoPath}${deta

Error message

ffmpeg could not extract first frame from ${videoPath}${detail}

What it means

Thrown by extractVideoFrameToBuffer when ffmpeg exited with a non-zero code OR failed to write the expected output PNG within the timeout. The trimmed stderr is appended (`detail`) so the underlying ffmpeg complaint is surfaced rather than swallowed. This is the non-timeout failure branch, complementing the timeout branch at line 505.

Source

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

      "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)
    : readFileSync(framePath);
  if (!buffer) {
    throw new Error(`Could not extract a frame from video: ${framePath}`);
  }

View on GitHub (pinned to c2996c8626)

Solutions

  1. Read the appended ffmpeg stderr in the message — it names the actual decoder/format problem.
  2. Install a full ffmpeg build (e.g. the static `ffmpeg` with all GPL codecs) if the message indicates a missing decoder.
  3. Pre-extract the frame with your own ffmpeg invocation and pass the PNG via `--for`.
  4. Confirm the temp directory is writable (`mktemp -d`) if the error hints at output write failure.

Example fix

# before — ffmpeg lacks the decoder
hyperframes grade-compare --for hevc_clip.mp4 --grades g.json
# after — extract with a full ffmpeg, then compare the PNG
ffmpeg -i hevc_clip.mp4 -frames:v 1 frame.png
hyperframes grade-compare --for frame.png --grades g.json
Defensive patterns

Strategy: fallback

Validate before calling

// Probe the video with ffprobe before grading to catch codec issues
import { spawnSync } from "node:child_process";
function videoIsReadable(path: string): boolean {
  const r = spawnSync("ffprobe", ["-v", "error", "-select_streams", "v:0", "-show_entries", "stream=codec_name", path]);
  return r.status === 0 && /codec_name/.test(r.stdout.toString());
}

Try / catch

try {
  // run grade-compare on a video
} catch (err) {
  if (/ffmpeg could not extract/.test((err as Error).message))) {
    // read appended stderr, install missing codec, or pre-extract the frame
  }
}

Prevention

When it happens

Trigger: Passing `--for video.mp4` where ffmpeg runs to completion but errors: unsupported codec, unreadable container, missing decoder, permission denied on the temp dir, or an ffmpeg build without the needed codec flags.

Common situations: A minimal/static ffmpeg build lacking libx264 or HEVC support; a DRM-protected or truncated video; permission issues on the OS temp dir; an unsupported container like a raw stream with no demuxer.

Related errors


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