{"record":{"id":"2de661d08883d885","repo":"HKUDS/Vibe-Trading","slug":"missing-filename","errorCode":null,"errorMessage":"Missing filename","messagePattern":"Missing filename","errorType":"validation","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"agent/src/api/uploads_routes.py","lineNumber":128,"sourceCode":"            raise HTTPException(status_code=404, detail=f\"Shadow report not found: {shadow_id}.{format}\")\n\n        media_type = \"text/html; charset=utf-8\" if format == \"html\" else \"application/pdf\"\n        return FileResponse(\n            path,\n            media_type=media_type,\n            headers={\"Content-Disposition\": f'inline; filename=\"{shadow_id}.{format}\"'},\n        )\n\n    @app.post(\"/upload\", dependencies=[Depends(require_auth)])\n    async def upload_file(file: UploadFile):\n        \"\"\"Upload any document or data file (max 50MB).\n\n        Accepts most common formats: PDF, Word, Excel, PowerPoint, images,\n        CSV/TSV, plain text, JSON, and TOML. Executables, executable-adjacent\n        source/config/template files, and archives are rejected.\n        \"\"\"\n        if not file.filename:\n            raise HTTPException(status_code=400, detail=\"Missing filename\")\n        filename = Path(file.filename).name\n        ext = Path(filename).suffix.lower()\n        if ext in _BLOCKED_UPLOAD_EXT or filename.lower() in _BLOCKED_UPLOAD_NAMES:\n            raise HTTPException(\n                status_code=400,\n                detail=\"This file type is not allowed for upload.\",\n            )\n\n        uploads_dir = _host_uploads_dir()\n        max_size = _host_max_upload_size()\n        chunk_size = _host_chunk_size()\n\n        safe_name = f\"{uuid.uuid4().hex}{ext}\"\n        dest = uploads_dir / safe_name\n        total_size = 0\n\n        try:\n            uploads_dir.mkdir(parents=True, exist_ok=True)","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/api/uploads_routes.py#L110-L146","documentation":"The upload endpoint requires a multipart file part with a filename. FastAPI reports file.filename as empty when the client sends a file part without a filename attribute, so the request is rejected with 400.","triggerScenarios":"POST /uploads with a multipart part named correctly but lacking filename=, or sending raw body/JSON instead of multipart/form-data.","commonSituations":"Hand-crafted curl requests, fetch/axios calls where the FormData was built incorrectly, or a proxy stripping the filename from the Content-Disposition header.","solutions":["Send multipart/form-data with a named file: curl -F 'file=@report.pdf'","In JS: formData.append('file', blob, 'report.pdf') — include the third filename argument","Verify the field name matches what the endpoint expects"],"exampleFix":"// before\nformData.append('file', blob)  // no filename in some clients\n// after\nformData.append('file', blob, 'report.pdf')","handlingStrategy":"type-guard","validationCode":"if not file_name: raise ValueError('multipart part needs a filename')","typeGuard":"def has_filename(fd) -> bool:\n    return bool(getattr(fd, 'filename', None))","tryCatchPattern":null,"preventionTips":["Always pass the filename argument in FormData.append","Use -F 'file=@name.ext' with curl"],"tags":["validation","upload","multipart","api"],"backgroundTag":"multipart-upload-invalid","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}