Zie619/n8n-workflows · error · HTTPException
Workflow file '{filename}' not found
Error message
Workflow file '{filename}' not found What it means
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'.
Source
Thrown at api_server.py:408
json_files = []
for subdir in workflows_path.iterdir():
if subdir.is_dir():
target_file = subdir / filename
if target_file.exists() and target_file.is_file():
# Verify the file is actually within workflows directory (defense in depth)
try:
target_file.resolve().relative_to(workflows_path)
json_files.append(target_file)
except ValueError:
# File is outside workflows directory
print(
f"Security: Blocked access to file outside workflows: {target_file}"
)
continue
if not json_files:
print(f"File {filename} not found in workflows directory")
raise HTTPException(
status_code=404, detail=f"Workflow file '{filename}' not found"
)
file_path = json_files[0]
# Final security check: Ensure file is within workflows directory
try:
file_path.resolve().relative_to(workflows_path)
except ValueError:
print(
f"Security: Blocked final attempt to access file outside workflows: {file_path}"
)
raise HTTPException(status_code=403, detail="Access denied")
return FileResponse(
str(file_path), media_type="application/json", filename=filename
)
except HTTPException:View on GitHub (pinned to 94007c1445)
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.
Example fix
# before json_files.append(target_file) only from subdirectories # after (accept top-level files too) candidates = [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()]
Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
def downloadable(workflows_dir, filename):
root = Path(workflows_dir).resolve()
for sub in root.iterdir():
if sub.is_dir():
cand = sub / filename
if cand.is_file():
try:
cand.resolve().relative_to(root)
return True
except ValueError:
pass
return False Try / catch
try:
r = client.get(f'/api/workflows/{name}/download')
r.raise_for_status()
except HTTPError as e:
if e.response.status_code == 404:
refresh_listing_and_remove(name) # stop offering stale downloads Prevention
- Reindex after any file move/rename/delete.
- Store files one subdirectory below workflows/ only.
- Refresh the listing before offering download links.
When it happens
Trigger: 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).
Common situations: Stale browser tab listing from before files were reorganized; renaming files outside the app; deeper nesting than the one-subdirectory layout.
Related errors
- Workflow file '{filename}' not found on filesystem
- Error downloading workflow: {str(e)}
- Workflow not found in database
- Error loading workflow: {str(e)}
- Workflow not found
AI-assisted analysis of Zie619/n8n-workflows@94007c1445 (2026-08-15).
Data as JSON: /api/errors/030ccf80413c7c24.
Report an issue: GitHub.