{"record":{"id":"95c466d6e19c5e98","repo":"affaan-m/ECC","slug":"all-takes-must-be-readable-local-files","errorCode":null,"errorMessage":"all takes must be readable local files","messagePattern":"all takes must be readable local files","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/forge.py","lineNumber":71,"sourceCode":"    root: str = \"stylepacks\",\n    base_video: str | None = None,\n    base_ratio: float = 0.35,\n    overlays: list[str] | None = None,\n    overlay_every: int = 4,\n    overlay_opacity: float = 0.3,\n    duration: float | None = None,\n    strength: float = 1.0,\n    grade_base: bool = True,\n    width: int | None = None,\n    height: int | None = None,\n    work: str = \"out/forge_work\",\n    plan: list[dict] | None = None,\n    fps: float | None = None,\n) -> Path:\n    out_path = Path(out)\n    validate_output(out_path)\n    if not takes or any(not Path(t).is_file() for t in takes):\n        raise ValueError(\"all takes must be readable local files\")\n    if base_video and not Path(base_video).is_file():\n        raise ValueError(\"base video must be a readable local file\")\n    if any(not Path(o).is_file() for o in (overlays or [])):\n        raise ValueError(\"all overlays must be readable local files\")\n    if fps is not None and (not math.isfinite(fps) or fps <= 0):\n        raise ValueError(\"fps must be finite and positive\")\n    sp = pack_mod.load(genre, root=root)\n    tgt = grade_mod.load_stats(sp.grade_path)\n    cad = cad_mod.load(sp.cadence_path)\n\n    # Geometry comes from the first take unless overridden; everything else is\n    # normalized to it so concat does not silently fail on a size mismatch.\n    info0 = frame_mod.probe(takes[0])\n    W = width or info0.width\n    H = height or info0.height\n    FPS = fps if fps is not None else info0.fps\n    if not math.isfinite(FPS) or FPS <= 0:\n        raise ValueError(\"source fps must be finite and positive; provide --fps\")","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/forge.py#L53-L89","documentation":"forge() validates its input media before doing any work: the takes list must be non-empty and every entry must be an existing regular file (Path(t).is_file()). If any take is missing, a directory, or the list is empty, it raises ValueError so ffprobe/ffmpeg never see a bad input.","triggerScenarios":"Calling forge with takes=[]; a take path that does not exist (typo, wrong cwd); a take pointing to a directory instead of a file; a broken symlink counted as a take.","commonSituations":"Shell glob that matched nothing (takes expanded to empty); relative paths resolved from a different working directory when invoked programmatically; files moved or deleted between planning and forging.","solutions":["Verify each take path exists with Path(t).is_file() before calling forge.","Use absolute paths in scripts so cwd changes do not break resolution.","Check the shell glob actually matched (e.g. ls takes/*.mov) — an unmatched glob passes the literal pattern or expands to nothing.","Remove directory entries and broken symlinks from the takes list."],"exampleFix":"# before\nforge('noir', takes, out='edit.mp4')  # one take was deleted\n\n# after\nfrom pathlib import Path\ntakes = [t for t in takes if Path(t).is_file()]\nif not takes:\n    raise SystemExit('no valid takes')\nforge('noir', takes, out='edit.mp4')","handlingStrategy":"validation","validationCode":"from pathlib import Path\n\ndef takes_ok(takes):\n    return bool(takes) and all(Path(t).is_file() for t in takes)","typeGuard":null,"tryCatchPattern":"try:\n    forge(genre, takes, out=out)\nexcept ValueError as e:\n    if 'takes' in str(e):\n        print('check take paths:', [t for t in takes if not Path(t).is_file()])\n    raise","preventionTips":["Filter takes with Path(t).is_file() before calling forge.","Use absolute paths so cwd changes don't break resolution.","Confirm shell globs matched at least one file before expanding to takes.","Exclude directories and broken symlinks from input lists."],"tags":["cli","validation","filesystem","input"],"backgroundTag":"file-not-found","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}