{"record":{"id":"030ccf80413c7c24","repo":"Zie619/n8n-workflows","slug":"workflow-file-filename-not-found","errorCode":null,"errorMessage":"Workflow file '{filename}' not found","messagePattern":"Workflow file '(.+?)' not found","errorType":"http","errorClass":"HTTPException","httpStatus":404,"severity":"error","filePath":"api_server.py","lineNumber":408,"sourceCode":"        json_files = []\n        for subdir in workflows_path.iterdir():\n            if subdir.is_dir():\n                target_file = subdir / filename\n                if target_file.exists() and target_file.is_file():\n                    # Verify the file is actually within workflows directory (defense in depth)\n                    try:\n                        target_file.resolve().relative_to(workflows_path)\n                        json_files.append(target_file)\n                    except ValueError:\n                        # File is outside workflows directory\n                        print(\n                            f\"Security: Blocked access to file outside workflows: {target_file}\"\n                        )\n                        continue\n\n        if not json_files:\n            print(f\"File {filename} not found in workflows directory\")\n            raise HTTPException(\n                status_code=404, detail=f\"Workflow file '{filename}' not found\"\n            )\n\n        file_path = json_files[0]\n\n        # Final security check: Ensure file is within workflows directory\n        try:\n            file_path.resolve().relative_to(workflows_path)\n        except ValueError:\n            print(\n                f\"Security: Blocked final attempt to access file outside workflows: {file_path}\"\n            )\n            raise HTTPException(status_code=403, detail=\"Access denied\")\n\n        return FileResponse(\n            str(file_path), media_type=\"application/json\", filename=filename\n        )\n    except HTTPException:","sourceCodeStart":390,"sourceCodeEnd":426,"githubUrl":"https://github.com/Zie619/n8n-workflows/blob/94007c1445d9258a7da116646b79473e7c7c3282/api_server.py#L390-L426","documentation":"A 404 from GET /api/workflows/{filename}/download when no candidate file is found: the handler scans only immediate subdirectories of workflows/ (subdir / filename, kept only if target.exists() and target.is_file() and resolve() stays inside workflows_path). An empty json_files list raises this error, with a server-side log line 'File {filename} not found in workflows directory'.","triggerScenarios":"Downloading a file that was deleted/moved after it appeared in a listing; a file at workflows/ top level (never scanned); a filename whose on-disk case differs; a file reachable only via a symlink resolving outside workflows/ (dropped by the containment check).","commonSituations":"Stale browser tab listing from before files were reorganized; renaming files outside the app; deeper nesting than the one-subdirectory layout.","solutions":["Verify the file exists at workflows/<subdir>/<filename> and re-run the search listing to get a fresh filename.","Reindex after filesystem changes so listings stop advertising missing files.","Keep all workflow JSONs exactly one subdirectory below workflows/.","Check the server log for 'Blocked access to file outside workflows' — that indicates a symlink/containment issue rather than absence."],"exampleFix":"# before\njson_files.append(target_file) only from subdirectories\n\n# after (accept top-level files too)\ncandidates = [p for p in [subdir / filename for subdir in workflows_path.iterdir() if subdir.is_dir()] + [workflows_path / filename] if p.exists() and p.is_file()]","handlingStrategy":"validation","validationCode":"from pathlib import Path\n\ndef downloadable(workflows_dir, filename):\n    root = Path(workflows_dir).resolve()\n    for sub in root.iterdir():\n        if sub.is_dir():\n            cand = sub / filename\n            if cand.is_file():\n                try:\n                    cand.resolve().relative_to(root)\n                    return True\n                except ValueError:\n                    pass\n    return False","typeGuard":null,"tryCatchPattern":"try:\n    r = client.get(f'/api/workflows/{name}/download')\n    r.raise_for_status()\nexcept HTTPError as e:\n    if e.response.status_code == 404:\n        refresh_listing_and_remove(name)  # stop offering stale downloads","preventionTips":["Reindex after any file move/rename/delete.","Store files one subdirectory below workflows/ only.","Refresh the listing before offering download links."],"tags":["fastapi","filesystem","http-404","download"],"backgroundTag":null,"analyzedSha":"94007c1445d9258a7da116646b79473e7c7c3282","analyzedAt":"2026-08-15T04:10:37.591Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}