{"record":{"id":"15eb258602947211","repo":"langflow-ai/langflow","slug":"profile-picture-safe-folder-safe-file-not-foun","errorCode":null,"errorMessage":"Profile picture {safe_folder}/{safe_file} not found","messagePattern":"Profile picture (.+?)/(.+?) not found","errorType":"http","errorClass":"HTTPException","httpStatus":404,"severity":"warning","filePath":"src/backend/base/langflow/api/v1/files.py","lineNumber":244,"sourceCode":"        candidate = os.path.realpath(os.path.join(allowed_base, safe_folder, safe_file))  # noqa: PTH118\n        if candidate != allowed_base and not candidate.startswith(allowed_base + os.sep):\n            raise HTTPException(status_code=404, detail=\"Profile picture not found\")\n        file_path = Path(candidate)\n\n        # Fallback to package bundled profile pictures if not found in config_dir\n        if not file_path.exists():\n            from langflow.initial_setup import setup\n\n            package_base = os.path.realpath(str(Path(setup.__file__).parent / \"profile_pictures\"))\n            package_candidate = os.path.realpath(os.path.join(package_base, safe_folder, safe_file))  # noqa: PTH118\n            if package_candidate != package_base and not package_candidate.startswith(package_base + os.sep):\n                raise HTTPException(status_code=404, detail=\"Profile picture not found\")\n\n            package_path = Path(package_candidate)\n            if package_path.exists():\n                file_path = package_path\n            else:\n                raise HTTPException(status_code=404, detail=f\"Profile picture {safe_folder}/{safe_file} not found\")\n\n        content_type = build_content_type_from_extension(extension)\n        # Read file directly from local filesystem using async file operations\n        file_content = await anyio.Path(file_path).read_bytes()\n        return StreamingResponse(BytesIO(file_content), media_type=content_type)\n\n    except HTTPException:\n        raise\n    except Exception as e:\n        raise HTTPException(status_code=500, detail=str(e)) from e\n\n\n@router.get(\"/profile_pictures/list\")\nasync def list_profile_pictures(\n    settings_service: Annotated[SettingsService, Depends(get_settings_service)],\n):\n    \"\"\"List profile pictures from local filesystem.\n","sourceCodeStart":226,"sourceCodeEnd":262,"githubUrl":"https://github.com/langflow-ai/langflow/blob/976ec789d2886a86de109c044d089d68e96c9a35/src/backend/base/langflow/api/v1/files.py#L226-L262","documentation":"Same download endpoint as above, but this variant means the resolved path passed the containment checks yet the file exists in neither config_dir/profile_pictures/<folder>/<file> nor the package-bundled langflow/initial_setup/setup/profile_pictures/<folder>/<file>. The folder name was allowed and the path was safe; the asset is simply absent in both lookup locations.","triggerScenarios":"GET /profile_pictures/{folder}/{file} where folder is in the allowed set but the named file was deleted, renamed, or never existed — e.g. referencing an avatar that only existed in an older Langflow version whose bundled set changed, or a file deleted from config_dir while the UI still caches its URL.","commonSituations":"Upgrading Langflow and the bundled avatar set changed while browsers serve cached profile URLs; a config_dir was wiped or migrated; a flow/user record references an avatar filename that was custom on another machine; typos in the filename.","solutions":["Call GET /api/v1/files/profile_pictures/list and confirm the exact '<folder>/<file>' string you are requesting appears in it","If missing, upload or copy the image into config_dir/profile_pictures/<allowed_folder>/ with the expected filename","After a version upgrade, refresh cached URLs (hard reload) since bundled avatars may have been renamed","Fall back to a default avatar client-side when this 404 is returned"],"exampleFix":"// before\nconst url = `/api/v1/files/profile_pictures/${folder}/${file}`;\n\n// after: verify against the listing before use\nconst { files } = (await axios.get('/api/v1/files/profile_pictures/list')).data;\nconst key = `${folder}/${file}`;\nconst url = files.includes(key)\n  ? `/api/v1/files/profile_pictures/${folder}/${file}`\n  : DEFAULT_AVATAR;","handlingStrategy":"fallback","validationCode":"const { files } = (await axios.get('/api/v1/files/profile_pictures/list')).data;\nconst exists = files.includes(`${folder}/${file}`);","typeGuard":null,"tryCatchPattern":"catch (e) { if (e.response?.status === 404 && e.response.data?.detail?.includes('not found')) return DEFAULT_AVATAR; throw e; }","preventionTips":["Persist the avatar key from the list endpoint on the user record instead of free-text filenames","After Langflow upgrades, re-run the listing to refresh avatar keys","Ship a bundled default avatar in the client as a fallback"],"tags":["http-404","profile-pictures","static-assets","filesystem"],"backgroundTag":null,"analyzedSha":"976ec789d2886a86de109c044d089d68e96c9a35","analyzedAt":"2026-08-14T18:23:12.227Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}