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
- Read the appended ffmpeg stderr in the message — it names the actual decoder/format problem.
- Install a full ffmpeg build (e.g. the static `ffmpeg` with all GPL codecs) if the message indicates a missing decoder.
- Pre-extract the frame with your own ffmpeg invocation and pass the PNG via `--for`.
- 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
- Install a full ffmpeg build with all GPL codecs for HEVC/AV1 input.
- Run `ffmpeg -version` to confirm codec support flags before grading videos.
- Pre-extract frames in your pipeline so the CLI never needs to decode video.
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
- ffmpeg timed out extracting first frame from ${videoPath}
- Could not extract a frame from video: ${framePath}
- Grade entry "${label}" must include a grading value
- --luts must include at least one LUT path
- --for <path> is required
AI-assisted analysis of heygen-com/hyperframes@c2996c8626 (2026-08-12).
Data as JSON: /api/errors/0b8c4ab09d788738.
Report an issue: GitHub.