affaan-m/ECC · error · FileNotFoundError
LUT not found
Error message
LUT not found: {lut} What it means
grade_clip applies a 3D LUT to a video clip via ffmpeg's lut3d filter. Before doing anything it resolves the LUT path to a Path and checks lut.exists(); if the file is not on disk it raises FileNotFoundError so the caller fails fast instead of letting ffmpeg die with a cryptic filter error. It is a guard against an invalid user-supplied path, not an internal fault.
Solutions
- Print and inspect the exact path: resolve it (Path(lut).resolve()) and check it exists with ls before re-running.
- Correct the path - fix typos and match case exactly; on Linux/macOS the filename is case-sensitive.
- If the pack is missing or incomplete, regenerate it by running mint.py so the .cube LUT is written to disk.
- Use an absolute path (or resolve relative paths against the pack root) instead of a cwd-dependent relative path.
- Wrap the call in try/except FileNotFoundError to surface a friendly message listing valid LUTs from the pack manifest.
Example fix
// before
grade_clip('shot.mp4', 'graded.mp4', lut='looks/teal_orange.CUBE')
// after
from pathlib import Path
lut = Path('looks/teal_orange.cube')
if not lut.exists():
raise SystemExit(f'LUT missing: {lut.resolve()}')
grade_clip('shot.mp4', 'graded.mp4', lut=lut) Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
lut = Path(lut_arg)
if not lut.is_file():
raise SystemExit(f'LUT does not exist: {lut.resolve()}')
if lut.suffix.lower() != '.cube':
raise SystemExit(f'expected a .cube LUT, got: {lut.name}') Try / catch
try:
grade_clip(src, dst, lut=lut)
except FileNotFoundError as e:
logger.error('LUT missing, check pack manifest: %s', e)
available = [p.name for p in pack_dir.glob('*.cube')]
raise SystemExit(f'available LUTs: {available}') from e Prevention
- Always take LUT paths from the StylePack manifest rather than typing them.
- Use absolute paths (Path(...).resolve()) so the result is cwd-independent.
- After minting a pack, assert every manifest LUT exists before starting a batch grade.
- Remember case sensitivity on Linux/macOS when naming .cube files.
When it happens
Trigger: Calling grade_clip(src, dst, lut=...) with a lut argument that points to a missing file: a typo in the filename, a .cube file that was never minted/copied into the pack, a relative path resolved from the wrong working directory, or a pack directory that was moved or deleted after minting.
Common situations: Hand-writing LUT paths in a pipeline config instead of taking them from the StylePack manifest; running the script from a different cwd than during testing so relative paths break; case-sensitive filesystems where 'Look.CUBE' vs 'look.cube' matters on Linux; partial style packs where LUT generation was skipped.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/e65c71164692e0e8.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-distillation/scripts/taste/grade.py:663
lut: str | Path,
strength: float = 1.0,
crf: int = 16,
) -> Path:
"""Apply a pack's .cube to a clip with ffmpeg. This is where the look happens.
Measured on three generations against the flashethereal pack: prompting
for the grade moved midtone a* from +1.9 to +2.8 across two paid attempts
and never touched contrast (23.4 / 19.3 / 19.2 against a target of 34.7).
Running the same footage through this function put chroma within a mean
absolute error of 1.4 and contrast at 34.9 against 34.7 - in one pass, at
no marginal cost, and identically every time.
``strength`` below 1.0 blends the graded result back toward the original,
for when the full pack look is too much for a particular shot.
"""
src, dst, lut = Path(src), Path(dst), Path(lut)
if not lut.exists():
raise FileNotFoundError(f"LUT not found: {lut}")
dst.parent.mkdir(parents=True, exist_ok=True)
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)View on GitHub (pinned to 8321021c54)