{"record":{"id":"0e0023ba713cf57b","repo":"jamiepine/voicebox","slug":"e-0e0023","errorCode":null,"errorMessage":"{e}","messagePattern":"\\{e\\}","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"backend/routes/history.py","lineNumber":60,"sourceCode":"async 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\n\n@router.get(\"/history/{generation_id}\", response_model=models.HistoryResponse)\nasync def get_generation(\n    generation_id: str,\n    db: Session = Depends(get_db),\n):\n    \"\"\"Get a generation by ID.\"\"\"\n    result = (","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/jamiepine/voicebox/blob/51f49dea198384b4eb6087b72c17057c6eb1c1cd/backend/routes/history.py#L42-L78","documentation":"Returned by POST /history/import when `export_import.import_generation_from_zip(content, db)` raises a ValueError, caught and re-raised as HTTP 400 with the exception's message. ValueErrors from this layer signal expected, client-correctable problems: malformed ZIP structure, missing manifest, schema mismatch, or duplicate id collision.","triggerScenarios":"Uploading a file that is not a valid .voicebox.zip export; the ZIP is missing its manifest/metadata file; the manifest's schema doesn't match the expected version; importing a generation whose id already exists (if the layer enforces uniqueness).","commonSituations":"Uploading an arbitrary ZIP instead of one produced by the /history/{id}/export endpoint; importing an export from a newer app version whose manifest format changed; corrupt download of the export.","solutions":["Read the error message — ValueErrors here are user-facing and explain the specific ZIP problem.","Only import ZIPs produced by GET /history/{id}/export for this app version.","If the manifest schema changed across versions, re-export from the source version after upgrading.","Open the ZIP locally and verify it contains the expected manifest + audio files before retrying."],"exampleFix":"// before: upload any zip\nupload(myZip);\n\n// after: only export-produced zips\nif (!file.name.endsWith('.voicebox.zip')) { alert('Use an exported generation ZIP'); return; }\nupload(file);","handlingStrategy":"try-catch","validationCode":"// Validate it's an exported voicebox zip before uploading\nif (!file.name.endsWith('.voicebox.zip')) { alert('Use an exported generation ZIP'); return; }\nawait upload(file);","typeGuard":"function looksLikeVoiceboxExport(file) {\n  return file && typeof file.name === 'string' && file.name.endsWith('.voicebox.zip');\n}","tryCatchPattern":"try {\n  const res = await fetch('/history/import', { method:'POST', body: form });\n  if (res.status === 400) {\n    const d = await res.json();\n    showImportError(d.detail); // carries the ValueError reason\n    return;\n  }\n} catch (e) { console.error(e); }","preventionTips":["Only import ZIPs produced by the export endpoint for this version.","Inspect the manifest inside the ZIP if the error is unclear.","Re-export from the source version after upgrades."],"tags":["fastapi","import","zip","validation","value-error","history","schema"],"backgroundTag":null,"analyzedSha":"51f49dea198384b4eb6087b72c17057c6eb1c1cd","analyzedAt":"2026-08-12T16:51:42.824Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}