{"record":{"id":"abce4b3528aa80b5","repo":"affaan-m/ECC","slug":"overlay-not-found-missing-paths","errorCode":null,"errorMessage":"--overlay not found: {missing paths}","messagePattern":"--overlay not found: (.+?)","errorType":"console","errorClass":"SystemExit","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/apply.py","lineNumber":391,"sourceCode":"        )\n        shots.append(s)\n        clock += float(t[\"used\"])\n\n    base_video_url = None\n    if base_video:\n        bp = Path(base_video)\n        if not bp.exists():\n            raise SystemExit(f\"--base-video not found: {bp}\")\n        base_video_url = falapi.upload(bp)\n        print(f\"  base video     : {bp.name} (frames pulled per shot timecode)\")\n\n    overlay_urls: list[str] = []\n    if overlays:\n        # Fail before any paid upload: forge() rejects a missing overlay\n        # later, which would strand every generated take without a manifest.\n        missing = [Path(o) for o in overlays if not Path(o).is_file()]\n        if missing:\n            raise SystemExit(\"--overlay not found: \" + \", \".join(str(m) for m in missing))\n        for o in overlays:\n            overlay_urls.append(falapi.upload(Path(o)))\n        print(f\"  overlays       : {len(overlay_urls)}\")\n\n    # Uploads are cached by (path, mtime, size), so the workers racing on the\n    # same handful of stills still only pay for each upload once.\n    lock = threading.Lock()\n    workers = max(1, min(int(concurrency), len(shots)))\n    print(f\"  generating     : {len(shots)} shot(s), {workers} worker(s) ...\")\n    with ThreadPoolExecutor(max_workers=workers) as pool:\n        list(pool.map(lambda s: _generate(s, base_video_url, lock), shots))\n\n    ok = [s for s in shots if s.video_url]\n    failed = [s for s in shots if not s.video_url]\n    for s in failed:\n        print(f\"  !! shot {s.index} failed: {s.error}\", file=sys.stderr)\n    if not ok:\n        raise SystemExit(\"every shot failed; nothing to compose\")","sourceCodeStart":373,"sourceCodeEnd":409,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/apply.py#L373-L409","documentation":"Pre-flight check in apply.py for --overlay paths: it deliberately fails before any paid upload because forge() would only reject a missing overlay later, stranding every generated take without a manifest. One or more overlay paths do not exist.","triggerScenarios":"Thrown at skills/taste-application/scripts/apply.py:391 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Fix or remove the missing overlay paths listed in the message","Verify each --overlay argument resolves to an existing file"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"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"}