{"record":{"id":"3103d95c0391a580","repo":"affaan-m/ECC","slug":"cannot-upload-file-does-not-exist-p-falapi","errorCode":null,"errorMessage":"cannot upload, file does not exist: {p}","messagePattern":"cannot upload, file does not exist: (.+?)","errorType":"exception","errorClass":"FalError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/taste/falapi.py","lineNumber":300,"sourceCode":"\n\ndef _cache_key(path: Path) -> tuple[str, int, int]:\n    st = path.stat()\n    return (str(path.resolve()), st.st_mtime_ns, st.st_size)\n\n\ndef upload(path: str | Path) -> str:\n    \"\"\"Upload a local file and return its URL, memoized per (path, mtime, size).\n\n    apply.py reuses the same handful of stills across every shot in a run and\n    across concurrent workers; without this cache each of those becomes a\n    redundant multi-megabyte POST.\n    \"\"\"\n    if not is_dry_run():\n        require_live()\n    p = Path(path)\n    if not p.exists():\n        raise FalError(f\"cannot upload, file does not exist: {p}\")\n\n    key = _cache_key(p)\n    with _UPLOAD_LOCK:\n        hit = _UPLOAD_CACHE.get(key)\n    if hit and (is_dry_run() == hit.startswith(DRY_RUN_HOST + \"/\")):\n        log.debug(\"upload cache hit: %s\", p.name)\n        return hit\n\n    if is_dry_run():\n        url = f\"{DRY_RUN_HOST}/uploads/{_digest(str(key))}/{p.name}\"\n        log.info(\"[dry-run] would upload %s (%d bytes) -> %s\", p, key[2], url)\n    else:\n        api_key()\n        try:\n            url = _fal().upload_file(str(p))\n        except Exception:\n            raise FalError(\"fal upload failed; provider details omitted\") from None\n        log.info(\"uploaded %s -> %s\", p.name, safe_url(url))","sourceCodeStart":282,"sourceCodeEnd":318,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/taste/falapi.py#L282-L318","documentation":"falapi.upload() validates that the local file exists before uploading it to fal.ai storage. If Path(path).exists() is false, it raises FalError with the resolved path, preventing a wasted POST against the provider. In dry-run mode the existence check still applies to live uploads while dry runs are exempt from require_live().","triggerScenarios":"Calling upload() (or upload_many() which delegates to it) with a path string that does not exist on disk — relative path resolved from the wrong working directory, file deleted between generation and upload, or a wrong extension/typo in the filename.","commonSituations":"Passing a path generated in a previous pipeline run whose temp/outputs directory was cleaned; running the script from a different cwd than expected so relative paths break; case-sensitivity mismatch (Linux vs macOS); symlink targets that were removed; snapshot files not yet written when upload is scheduled.","solutions":["Fix the path: print/inspect the resolved path in the error and correct the filename, extension, or working directory (use absolute paths where possible).","Check the file exists before calling: `from pathlib import Path; assert Path(p).is_file()` or guard in your pipeline before upload_many().","Regenerate the missing artifact first (e.g. re-run the step that produced the file) if it was cleaned up or never written.","On Linux/macOS verify case matches exactly and that symlinks resolve (`ls -l`, `readlink -f`)."],"exampleFix":"# before\nurl = upload(\"outputs/asset.glb\")  # FalError: cannot upload, file does not exist: outputs/asset.glb\n\n# after\nfrom pathlib import Path\np = Path(\"outputs/asset.glb\").resolve()\nif not p.is_file():\n    raise FileNotFoundError(f\"regenerate artifact first: {p}\")\nurl = upload(str(p))","handlingStrategy":"validation","validationCode":"from pathlib import Path\np = Path(path)\nif not p.is_file():\n    raise FileNotFoundError(f\"artifact missing before upload: {p.resolve()}\")","typeGuard":"def is_uploadable(path: object) -> bool:\n    from pathlib import Path\n    return isinstance(path, (str, Path)) and Path(path).is_file()","tryCatchPattern":"try:\n    url = upload(path)\nexcept FalError as e:\n    if str(e).startswith(\"cannot upload, file does not exist\"):\n        raise FileNotFoundError(path) from e\n    raise","preventionTips":["Use absolute, resolved paths when calling upload()/upload_many()","Assert artifact existence immediately after the generating step, before scheduling the upload","Be aware of cwd differences between dev shell, CI, and containers when using relative paths","On Linux, double-check filename case; on cleanup jobs, don't delete outputs before their upload completes"],"tags":["python","file","path","validation"],"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"}