affaan-m/ECC · error · RuntimeError
ffmpeg grade failed
Error message
ffmpeg grade failed: {proc.stderr[-400:]} What it means
grade_clip shells out to ffmpeg with a lut3d video filter and libx264 encoding. If ffmpeg exits with a non-zero return code, the wrapper raises RuntimeError containing the last 400 characters of ffmpeg's stderr, because Python itself cannot diagnose ffmpeg-level failures. The real cause is always in the captured stderr text.
Solutions
- Read the stderr text embedded in the exception message - it names the specific ffmpeg error (filter parse error, codec missing, permission, etc.).
- Validate the LUT separately: run ffmpeg -i src -vf lut3d=file='your.cube' -frames:v 1 out.png to isolate whether the LUT or the clip is the problem.
- Check ffmpeg capabilities: ffmpeg -version and confirm libx264 appears in the configuration; if not, install a full ffmpeg build (e.g. via conda, brew, or a static build).
- Re-encode or remux the source if the input is corrupt/unsupported (ffmpeg -i src -c copy fixed.mp4), then grade the fixed file.
- Verify the destination directory is writable and has free space; test write with touch dst_dir/.probe.
Defensive patterns
Strategy: try-catch
Validate before calling
import shutil
assert shutil.which('ffmpeg'), 'ffmpeg not on PATH'
info = subprocess.run(['ffmpeg','-version'], capture_output=True, text=True)
assert 'libx264' in info.stderr or 'libx264' in info.stdout, 'ffmpeg lacks libx264'
assert Path(lut).is_file(), f'LUT missing: {lut}' Try / catch
try:
grade_clip(src, dst, lut=lut)
except RuntimeError as e:
ffmpeg_err = str(e).split(': ', 1)[-1]
logger.error('ffmpeg grading failed; stderr tail: %s', ffmpeg_err)
# branch on the stderr content: LUT parse error vs codec vs permissions Prevention
- Keep a full-featured ffmpeg build (libx264 + lut3d support) on PATH in every environment.
- Probe each source with ffprobe before grading to catch unsupported/corrupt inputs early.
- Ensure destination directories exist and are writable before launching batches.
- Validate LUT files once after minting (render a single test frame through lut3d).
When it happens
Trigger: Any ffmpeg failure while grading: a malformed or unsupported .cube LUT the filter rejects, an unreadable/corrupt or unsupported input container/codec, a destination path that is not writable, or a broken ffmpeg install missing libx264.
Common situations: LUT exported with wrong size/format for lut3d (e.g. 1D LUT or non-cube LUT); ffmpeg on the system built without libx264; input video with a codec OpenCV/ffmpeg cannot decode; disk full or dst in a read-only directory; an old ffmpeg that lacks lut3d support.
Related errors
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/a272c0e8135b2b8f.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-distillation/scripts/taste/grade.py:683
s = max(0.0, min(1.0, float(strength)))
if s >= 0.999:
vf = f"lut3d=file='{lut.as_posix()}'"
else:
# Blend graded over original so partial looks stay available.
vf = (
f"split=2[a][b];[b]lut3d=file='{lut.as_posix()}'[g];"
f"[a][g]blend=all_mode=normal:all_opacity={s:.3f}"
)
cmd = [
"ffmpeg", "-nostdin", "-loglevel", "error", "-y", "-i", str(src),
"-vf", vf, "-c:v", "libx264", "-crf", str(crf), "-pix_fmt", "yuv420p",
"-c:a", "copy", str(dst),
]
proc = subprocess.run(cmd, capture_output=True, text=True)
if proc.returncode != 0:
raise RuntimeError(f"ffmpeg grade failed: {proc.stderr[-400:]}")
return dst
def grade_clip_adaptive(
src: str | Path,
dst: str | Path,
target: GradeStats,
strength: float = 1.0,
lut_size: int = 33,
n_frames: int = 32,
keep_lut: str | Path | None = None,
) -> Path:
"""Measure the clip, bake a LUT *for that clip*, then apply it.
Prefer this over :func:`grade_clip` for anything generated.
``look.cube`` is baked against a canonical neutral stand-in, because when
a pack is minted there is no way to know what footage it will meet. ThatView on GitHub (pinned to 8321021c54)