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

  1. 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.
  2. Ensure ffmpeg and ffprobe are installed and resolvable: `ffmpeg -version` and `ffprobe -version` must succeed in the same shell/env the render runs in.
  3. Pass explicit paths via options: `analyzeMediaGrade(path, { ffmpegPath: "/usr/bin/ffmpeg", ffprobePath: "/usr/bin/ffprobe" })`.
  4. Verify the path exists and is a complete file (`fs.statSync`), not a pipe or partial write.
  5. 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

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


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