heygen-com/hyperframes · error · Error
grade analysis failed for ${mediaPath}: ${message}
Error message
grade analysis failed for ${mediaPath}: ${message} What it means
The catch-all wrapper in analyzeMediaGrade(). Every failure in the probe-or-measure sequence — execFileSync throwing (binary missing, non-zero exit, timeout), or summarizeFrames() throwing error 340 — is re-thrown with the media path prepended and the underlying message preserved. It is the single error surface callers see from the public analyzeMediaGrade() API.
Source
Thrown at packages/core/src/mediaGradeAnalyzer.ts:348
mediaPath,
"-vf",
filters,
"-frames:v",
String(SAMPLE_FRAMES),
"-f",
"null",
"-",
],
{
encoding: "utf8",
timeout: Number(process.env.HYPERFRAMES_ANALYZE_TIMEOUT_MS) || DEFAULT_TIMEOUT_MS,
stdio: ["ignore", "pipe", "pipe"],
},
);
return summarizeMediaTreatmentAnalysis(probe, parseMediaTreatmentSignalStats(raw));
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
throw new Error(`grade analysis failed for ${mediaPath}: ${message}`);
}
}
export function formatMeasuredNote(
mediaPath: string,
measured: MediaTreatmentMeasurements,
): string {
return `media-use: measured ${basename(mediaPath)}: frames=${measured.frames}, YMIN=${measured.yMin}, YLOW=${measured.yLow}, YAVG=${measured.yAvg}, YHIGH=${measured.yHigh}, YMAX=${measured.yMax}, UAVG=${measured.uAvg}, VAVG=${measured.vAvg}; adjust is a starting suggestion`;
}
View on GitHub (pinned to c2996c8626)
Solutions
- Read the `${message}` suffix first — ENOENT means the ffmpeg/ffprobe binary is missing, a numeric exit code means ffmpeg rejected the input, and `Command timed out` means raise HYPERFRAMES_ANALYZE_TIMEOUT_MS.
- Ensure ffmpeg and ffprobe are installed and resolvable: `ffmpeg -version` and `ffprobe -version` must succeed in the same shell/env the render runs in.
- Pass explicit paths via options: `analyzeMediaGrade(path, { ffmpegPath: "/usr/bin/ffmpeg", ffprobePath: "/usr/bin/ffprobe" })`.
- Verify the path exists and is a complete file (`fs.statSync`), not a pipe or partial write.
- If the suffix is the error-340 message, follow the 340 remediation (no analyzable video frames).
Example fix
// before
const a = analyzeMediaGrade(mediaPath);
// after
try {
const a = analyzeMediaGrade(mediaPath, { ffmpegPath: process.env.FFMPEG_PATH });
} catch (e) {
if (!/grade analysis failed/.test(String(e))) throw e;
console.warn(`skipping grade analysis: ${e.message}`); // non-fatal, fall back to default grade
} Defensive patterns
Strategy: try-catch
Validate before calling
import { existsSync, statSync } from "node:fs";
import { execFileSync } from "node:child_process";
function preflightMedia(path: string, ffmpegPath = "ffmpeg", ffprobePath = "ffprobe"): void {
if (!existsSync(path) || !statSync(path).isFile()) throw new Error(`media not found: ${path}`);
for (const bin of [ffmpegPath, ffprobePath]) {
try { execFileSync(bin, ["-version"], { stdio: "ignore" }); }
catch { throw new Error(`missing binary on PATH: ${bin}`); }
}
} Type guard
null
Try / catch
let analysis;
try {
analysis = analyzeMediaGrade(mediaPath, { ffmpegPath, ffprobePath });
} catch (e) {
const msg = e instanceof Error ? e.message : String(e);
if (/Command timed out|ENOENT|grade analysis failed/.test(msg)) {
logger.warn(`grade analysis unavailable (${msg}); using default grade`);
analysis = defaultAnalysis();
} else throw e;
} Prevention
- Install ffmpeg+ffprobe in every environment that runs the render (Docker, CI, local).
- Treat grade analysis as non-fatal: wrap in try/catch and degrade to a default grade.
- Pass explicit ffmpegPath/ffprobePath rather than relying on PATH in containers.
- Set HYPERFRAMES_ANALYZE_TIMEOUT_MS high enough for the largest source you grade.
When it happens
Trigger: Calling analyzeMediaGrade(mediaPath, { ffmpegPath?, ffprobePath? }) when: ffmpeg/ffprobe binaries are not on PATH (ENOENT), the input path does not exist or is unreadable, ffmpeg exits non-zero on a malformed file, the run exceeds `HYPERFRAMES_ANALYZE_TIMEOUT_MS` (default 15000ms), or the inner parser produced zero frames (error 340). probeMedia() itself swallows errors and returns `unknown`, so it never reaches this catch.
Common situations: CI/containers where ffmpeg is not installed; Docker image missing the ffmpeg dependency; Windows hosts where ffmpeg is not on PATH; rendering on a slow machine where 5-frame sampling of a long GOP video exceeds 15s; passing a relative path from the wrong cwd; pointing at a file still being written by an upstream render step.
Related errors
- FFmpeg returned no analyzable video frames
- [build-zip] ffmpeg-static binary missing at ${ffmpegBinary}.
- Unsupported output extension: ${ext}. Use .webm (VP9 alpha),
- ffmpeg and ffprobe are required. Install: ${getFFmpegInstall
- No frames produced from ${inputPath}. Decoder stderr: ${deco
AI-assisted analysis of heygen-com/hyperframes@c2996c8626 (2026-08-12).
Data as JSON: /api/errors/b0d77885a1ab3939.
Report an issue: GitHub.