{"record":{"id":"25c2fa2cb0a87d85","repo":"jamiepine/voicebox","slug":"file-too-large-maximum-size-is-max-file-size","errorCode":null,"errorMessage":"File too large. Maximum size is {MAX_FILE_SIZE / (1024 * 1024)}MB","messagePattern":"File too large\\. Maximum size is (.+?)MB","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"backend/routes/history.py","lineNumber":52,"sourceCode":"\n@router.get(\"/history/stats\")\nasync def get_stats(db: Session = Depends(get_db)):\n    \"\"\"Get generation statistics.\"\"\"\n    return await history.get_generation_stats(db)\n\n\n@router.post(\"/history/import\")\nasync def import_generation(\n    file: UploadFile = File(...),\n    db: Session = Depends(get_db),\n):\n    \"\"\"Import a generation from a ZIP archive.\"\"\"\n    MAX_FILE_SIZE = 50 * 1024 * 1024\n\n    content = await file.read()\n\n    if len(content) > MAX_FILE_SIZE:\n        raise HTTPException(\n            status_code=400, detail=f\"File too large. Maximum size is {MAX_FILE_SIZE / (1024 * 1024)}MB\"\n        )\n\n    try:\n        result = await export_import.import_generation_from_zip(content, db)\n        return result\n    except ValueError as e:\n        raise HTTPException(status_code=400, detail=str(e))\n    except Exception as e:\n        raise HTTPException(status_code=500, detail=str(e))\n\n\n@router.delete(\"/history/failed\")\nasync def clear_failed_generations(db: Session = Depends(get_db)):\n    \"\"\"Delete every generation with status='failed'. Used by the UI's 'Clear failed' button (#410).\"\"\"\n    count = await history.delete_failed_generations(db)\n    return {\"deleted\": count}\n","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/jamiepine/voicebox/blob/51f49dea198384b4eb6087b72c17057c6eb1c1cd/backend/routes/history.py#L34-L70","documentation":"Returned by POST /history/import when `len(content) > MAX_FILE_SIZE` where MAX_FILE_SIZE is hardcoded to 50 * 1024 * 1024 (50 MB). The entire upload is read into memory via `await file.read()` before the check, then rejected with HTTP 400 (note: the status code is 400, though semantically 413 would be more appropriate). This endpoint imports a previously-exported generation ZIP.","triggerScenarios":"Uploading a generation ZIP larger than 50 MB; the entire file is already buffered in memory by the time the size is checked, so a 100 MB upload wastes RAM before being rejected.","commonSituations":"Re-importing a generation whose embedded audio is large; exporting+re-importing after the audio was upscaled; a ZIP bomb or maliciously large archive.","solutions":["Ensure the imported ZIP is under 50 MB — if the contained audio is large, the export ZIP will exceed this.","If larger imports are needed, raise MAX_FILE_SIZE in backend/routes/history.py and the reverse proxy body limit accordingly.","Consider changing the status code to 413 for semantic correctness if you touch this code.","Stream-check the size during read instead of after full buffering to avoid holding oversized payloads in memory."],"exampleFix":"# before\nMAX_FILE_SIZE = 50 * 1024 * 1024\nif len(content) > MAX_FILE_SIZE:\n    raise HTTPException(status_code=400, detail=f\"File too large...\")\n\n# after\nMAX_FILE_SIZE = 50 * 1024 * 1024\nif len(content) > MAX_FILE_SIZE:\n    raise HTTPException(status_code=413, detail=f\"File too large...\")","handlingStrategy":"validation","validationCode":"const MAX = 50 * 1024 * 1024;\nif (file.size > MAX) { alert(`ZIP exceeds ${MAX/1048576} MB`); return; }\nawait upload(file);","typeGuard":"function withinImportZipLimit(file, limitBytes = 50 * 1024 * 1024) {\n  return file && typeof file.size === 'number' && file.size <= limitBytes;\n}","tryCatchPattern":"try {\n  const res = await fetch('/history/import', { method:'POST', body: form });\n  if (res.status === 400 && /too large/i.test((await res.json()).detail)) {\n    alert('Import ZIP too large'); return;\n  }\n} catch (e) { console.error(e); }","preventionTips":["Check file.size before uploading.","Keep export audio small enough to fit the 50 MB import limit.","Raise MAX_FILE_SIZE server-side if larger imports are needed (and the proxy limit)."],"tags":["fastapi","file-upload","import","zip","size-limit","history"],"backgroundTag":null,"analyzedSha":"51f49dea198384b4eb6087b72c17057c6eb1c1cd","analyzedAt":"2026-08-12T16:51:42.824Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}