{"record":{"id":"f34bda67f5741b8e","repo":"odysseus-dev/odysseus","slug":"file-not-found-f34bda","errorCode":null,"errorMessage":"File not found","messagePattern":"File not found","errorType":"http","errorClass":"HTTPException","httpStatus":404,"severity":"error","filePath":"routes/upload_routes.py","lineNumber":169,"sourceCode":"        from src.constants import UPLOAD_DIR\n        return os.path.realpath(getattr(upload_handler, \"upload_dir\", UPLOAD_DIR))\n\n    def _path_inside_upload_dir(path: str) -> bool:\n        try:\n            return os.path.commonpath([_upload_root(), os.path.realpath(path)]) == _upload_root()\n        except Exception:\n            return False\n\n    def _resolve_upload_path(file_id: str) -> str:\n        from src.constants import UPLOAD_DIR\n        upload_root = getattr(upload_handler, \"upload_dir\", UPLOAD_DIR)\n        direct = os.path.join(upload_root, file_id)\n        if os.path.lexists(direct):\n            if not _path_inside_upload_dir(direct):\n                raise HTTPException(403, \"Access denied\")\n            if os.path.isfile(direct):\n                return direct\n            raise HTTPException(404, \"File not found\")\n\n        for root, _dirs, files in os.walk(upload_root, followlinks=False):\n            if file_id not in files:\n                continue\n            path = os.path.join(root, file_id)\n            if not _path_inside_upload_dir(path):\n                raise HTTPException(403, \"Access denied\")\n            if os.path.isfile(path):\n                return path\n            raise HTTPException(404, \"File not found\")\n\n        raise HTTPException(404, \"File not found\")\n\n    def _valid_session_id_for_owner(db, session_id: str | None, owner: str | None) -> str | None:\n        if not session_id:\n            return None\n        sess = db.query(DbSession).filter(DbSession.id == session_id).first()\n        if not sess:","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/routes/upload_routes.py#L151-L187","documentation":"HTTP 404 from _resolve_upload_path when the direct path under upload_root exists but is not a regular file — file_id names a directory or special file. lexists succeeded and the inside-root check passed, but os.path.isfile failed.","triggerScenarios":"Download request whose file_id equals a directory name inside uploads (such as 'sessions' or 'gallery'), or a fifo/socket/device file occupying that name.","commonSituations":"Client constructing ids from filenames that happen to collide with directory names; upload id schema changed so old ids now collide with directory names; partial upload left a stub non-file artifact.","solutions":["Use ids returned by the upload API only; directory names are never valid ids","List valid ids via the upload/gallery listing endpoints when in doubt","Remove stray non-file artifacts from the uploads root if one shadows a real id"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// verify the id refers to a listed upload before fetching\nconst files = await listUploads();\nif (!files.some(f => f.id === fileId)) throw new Error('unknown id');","typeGuard":"function isKnownUploadId(id: string, known: string[]): boolean {\n  return known.includes(id);\n}","tryCatchPattern":"if (resp.status === 404) { removeFromLocalCache(fileId); }","preventionTips":["Don't derive ids from filenames — directories share the namespace","Prune client caches of deleted ids on 404"],"tags":["http","uploads","not-found"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}