{"record":{"id":"37b57c9bfd66cc8b","repo":"AUTOMATIC1111/stable-diffusion-webui","slug":"file-cannot-be-fetched-filename-must-be-in-one","errorCode":null,"errorMessage":"File cannot be fetched: {filename}. Must be in one of directories registered by extra pages.","messagePattern":"File cannot be fetched: (.+?)\\. Must be in one of directories registered by extra pages\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"modules/ui_extra_networks.py","lineNumber":104,"sourceCode":"\r\n    return res\r\n\r\ndef register_page(page):\r\n    \"\"\"registers extra networks page for the UI; recommend doing it in on_before_ui() callback for extensions\"\"\"\r\n\r\n    extra_pages.append(page)\r\n    allowed_dirs.clear()\r\n    allowed_dirs.update(set(sum([x.allowed_directories_for_previews() for x in extra_pages], [])))\r\n\r\n\r\ndef fetch_file(filename: str = \"\"):\r\n    from starlette.responses import FileResponse\r\n\r\n    if not os.path.isfile(filename):\r\n        raise HTTPException(status_code=404, detail=\"File not found\")\r\n\r\n    if not any(Path(x).absolute() in Path(filename).absolute().parents for x in allowed_dirs):\r\n        raise ValueError(f\"File cannot be fetched: {filename}. Must be in one of directories registered by extra pages.\")\r\n\r\n    ext = os.path.splitext(filename)[1].lower()[1:]\r\n    if ext not in allowed_preview_extensions():\r\n        raise ValueError(f\"File cannot be fetched: {filename}. Extensions allowed: {allowed_preview_extensions()}.\")\r\n\r\n    # would profit from returning 304\r\n    return FileResponse(filename, headers={\"Accept-Ranges\": \"bytes\"})\r\n\r\n\r\ndef fetch_cover_images(page: str = \"\", item: str = \"\", index: int = 0):\r\n    from starlette.responses import Response\r\n\r\n    page = next(iter([x for x in extra_pages if x.name == page]), None)\r\n    if page is None:\r\n        raise HTTPException(status_code=404, detail=\"File not found\")\r\n\r\n    metadata = page.metadata.get(item)\r\n    if metadata is None:\r","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/AUTOMATIC1111/stable-diffusion-webui/blob/82a973c04367123ae98bd9abdf80d9eda9b910e2/modules/ui_extra_networks.py#L86-L122","documentation":"Second guard in fetch_file(): the requested filename's absolute path must have one of the registered allowed_dirs (directories declared by extra-network pages via allowed_directories_for_previews()) among its parents. Anything outside those roots — including ../ traversal attempts — is rejected with this ValueError, making it also a path-traversal defense.","triggerScenarios":"A request whose filename resolves outside every allowed root: absolute paths pointing elsewhere on disk (/etc/passwd), or relative paths with enough ../ segments to climb out of the models directory. Also legitimate-looking requests when allowed_dirs is empty because no extra page has registered preview directories yet.","commonSituations":"Security scanners probing the endpoint; a custom extension registering a page but forgetting allowed_directories_for_previews(); bookmarked/crafted URLs referencing directories that were never registered.","solutions":["Only request files that live inside a registered extra-networks directory (embeddings/, models/Lora/, etc.)","If you author an extra-networks page, implement allowed_directories_for_previews() to return your preview dirs so they become fetchable","For external assets, serve them from your own route instead of trying to use this endpoint"],"exampleFix":"# extension authors: register your preview directory\nclass MyPage(extra_networks_page.ExtraNetworksPage):\n    def allowed_directories_for_previews(self):\n        return [os.path.join(my_extension_dir, 'previews')]","handlingStrategy":"validation","validationCode":"from pathlib import Path\nfrom modules import ui_extra_networks\ndef is_fetchable(filename):\n    p = Path(filename).absolute()\n    return p.is_file() and any(Path(x).absolute() in p.parents for x in ui_extra_networks.allowed_dirs)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never point preview requests outside registered extra-network directories","Extension pages must implement allowed_directories_for_previews()","Treat this ValueError in logs as a signal of probing or misconfigured paths"],"tags":["security","path-traversal","http","extra-networks","preview"],"backgroundTag":null,"analyzedSha":"82a973c04367123ae98bd9abdf80d9eda9b910e2","analyzedAt":"2026-08-14T16:46:43.225Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}