{"record":{"id":"2627940c409ce458","repo":"Zie619/n8n-workflows","slug":"error-downloading-workflow-str-e","errorCode":null,"errorMessage":"Error downloading workflow: {str(e)}","messagePattern":"Error downloading workflow: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":500,"severity":"error","filePath":"api_server.py","lineNumber":430,"sourceCode":"        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:\n        raise\n    except Exception as e:\n        print(f\"Error downloading workflow {filename}: {str(e)}\")\n        raise HTTPException(\n            status_code=500, detail=f\"Error downloading workflow: {str(e)}\"\n        )\n\n\n@app.get(\"/api/workflows/{filename}/diagram\")\nasync def get_workflow_diagram(filename: str, request: Request):\n    \"\"\"Get Mermaid diagram code for workflow visualization.\"\"\"\n    try:\n        # Security: Validate filename to prevent path traversal\n        if not validate_filename(filename):\n            print(f\"Security: Blocked path traversal attempt for filename: {filename}\")\n            raise HTTPException(status_code=400, detail=\"Invalid filename format\")\n\n        # Security: Rate limiting\n        client_ip = request.client.host if request.client else \"unknown\"\n        if not check_rate_limit(client_ip):\n            raise HTTPException(\n                status_code=429, detail=\"Rate limit exceeded. Please try again later.\"","sourceCodeStart":412,"sourceCodeEnd":448,"githubUrl":"https://github.com/Zie619/n8n-workflows/blob/94007c1445d9258a7da116646b79473e7c7c3282/api_server.py#L412-L448","documentation":"The catch-all 500 for GET /api/workflows/{filename}/download. HTTPExceptions re-raise untouched, so reaching this handler means an unexpected exception while building or serving the FileResponse — e.g. the file disappearing between the scan and the response, or FileResponse failing to stat/open the path. The exception is printed server-side ('Error downloading workflow {filename}: ...') and wrapped into the 500 detail.","triggerScenarios":"TOCTOU: file exists during the scan but is deleted before FileResponse opens it; permission error when the server process reads the file; FileResponse construction failing on a path that is actually a directory or a broken symlink that passed earlier checks.","commonSituations":"Concurrent cleanup scripts pruning workflows/; permissions changed while the server runs; exotic filesystems where stat succeeds but open fails.","solutions":["Read the detail text and the server console for the exact exception.","Verify the file is readable by the server process user: ls -l workflows/<subdir>/<file> and sudo -u <user> cat <path>.","Re-run the listing and retry the download with a filename known to currently exist.","For recurring races, index/read files under a stable snapshot or pause cleanup during reindex."],"exampleFix":"# before\nreturn FileResponse(str(file_path), media_type='application/json', filename=filename)\n\n# after (fail with a clear 410 when the file vanished mid-request)\nif not file_path.is_file():\n    raise HTTPException(status_code=410, detail='Workflow file no longer available')\nreturn FileResponse(str(file_path), media_type='application/json', filename=filename)","handlingStrategy":"try-catch","validationCode":"import requests\n\ndef file_served(base, name):\n    r = requests.head(f'{base}/api/workflows/{name}/download', timeout=5,\n                      allow_redirects=True)\n    return r.status_code == 200","typeGuard":null,"tryCatchPattern":"try:\n    save(client.get(f'/api/workflows/{name}/download'))\nexcept HTTPError as e:\n    if e.response.status_code == 500:\n        log(e.response.json()['detail'])  # contains the underlying OS error\n        revalidate_file_on_disk(name)","preventionTips":["Avoid deleting/renaming files while downloads are in flight.","Keep read permissions stable for the server user.","Retry once after confirming the file still exists in a fresh listing."],"tags":["fastapi","filesystem","race-condition","http-500","download"],"backgroundTag":null,"analyzedSha":"94007c1445d9258a7da116646b79473e7c7c3282","analyzedAt":"2026-08-15T04:10:37.591Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}