{"record":{"id":"326f4405035cbf2f","repo":"calesthio/OpenMontage","slug":"image-not-found-image-path-326f44","errorCode":null,"errorMessage":"Image not found: {image_path}","messagePattern":"Image not found: (.+?)","errorType":"exception","errorClass":"FileNotFoundError","httpStatus":null,"severity":"error","filePath":"tools/video/_shared.py","lineNumber":428,"sourceCode":"            raise RuntimeError(f\"HeyGen generation failed: {data.get('error', 'Unknown')}\")\n\n        time.sleep(min(interval, max(0.0, deadline - time.time())))\n        interval = min(interval * 1.2, 30.0)\n\n    raise TimeoutError(f\"HeyGen execution {execution_id} timed out after {timeout}s\")\n\n\ndef upload_image_fal(image_path: str) -> str:\n    \"\"\"Upload a local image to fal.ai storage and return a public URL.\"\"\"\n    import requests\n\n    api_key = os.environ.get(\"FAL_KEY\") or os.environ.get(\"FAL_AI_API_KEY\")\n    if not api_key:\n        raise RuntimeError(\"FAL_KEY or FAL_AI_API_KEY required for image upload\")\n\n    path = Path(image_path)\n    if not path.exists():\n        raise FileNotFoundError(f\"Image not found: {image_path}\")\n\n    suffix = path.suffix.lower()\n    content_type = {\"png\": \"image/png\", \"jpg\": \"image/jpeg\", \"jpeg\": \"image/jpeg\", \"webp\": \"image/webp\"}.get(\n        suffix.lstrip(\".\"), \"image/png\"\n    )\n\n    # Initiate upload\n    init_resp = requests.post(\n        \"https://rest.alpha.fal.ai/storage/upload/initiate\",\n        headers={\"Authorization\": f\"Key {api_key}\", \"Content-Type\": \"application/json\"},\n        json={\"content_type\": content_type, \"file_name\": path.name},\n        timeout=30,\n    )\n    init_resp.raise_for_status()\n    data = init_resp.json()\n\n    # Upload file content\n    put_resp = requests.put(","sourceCodeStart":410,"sourceCodeEnd":446,"githubUrl":"https://github.com/calesthio/OpenMontage/blob/95e1c3d0ab93482159818560f6a8c8e866b9139f/tools/video/_shared.py#L410-L446","documentation":"Raised by upload_image_fal as FileNotFoundError when the local image path passed in does not exist on disk. It is a pre-flight check before any network activity, so seeing it means no upload was attempted. Paths are used as-is; no search or workspace resolution is performed.","triggerScenarios":"Relative path resolved against a different cwd (subprocess, lambda, background worker); file deleted by a cleanup step between generation and upload; typo or wrong extension in the path; forward/backslash mismatch across platforms.","commonSituations":"Temp-file race where the generator wrote to /tmp but the uploader runs after tmp reaping; agent pipelines passing a URL instead of a local path to an upload-local-file helper.","solutions":["Verify with Path(image_path).exists() before calling","Pass absolute paths (Path(...).resolve()) to avoid cwd drift","If you have a URL already, skip upload_image_fal — it is only for local files","Regenerate the source image if a cleanup step removed it"],"exampleFix":"# before\nupload_image_fal(\"assets/face.png\")   # run from another cwd\n# after\nfrom pathlib import Path\nupload_image_fal(str(Path(\"assets/face.png\").resolve()))","handlingStrategy":"validation","validationCode":"from pathlib import Path\np = Path(image_path).resolve()\nif not p.is_file():\n    raise FileNotFoundError(f\"generate the image first: {image_path}\")\nupload_image_fal(str(p))","typeGuard":"def is_local_image(path: Any) -> bool:\n    return isinstance(path, (str, Path)) and Path(path).is_file()","tryCatchPattern":null,"preventionTips":["Always pass absolute resolved paths to upload helpers","Verify the upstream generation succeeded before the upload step","Don't pass URLs to a local-file uploader; download first or use URL inputs directly"],"tags":["fal","file-not-found","paths","upload"],"backgroundTag":null,"analyzedSha":"95e1c3d0ab93482159818560f6a8c8e866b9139f","analyzedAt":"2026-08-15T06:31:20.014Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}