jamiepine/voicebox · error · HTTPException

{e}

Error message

{e}

What it means

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.

Source

Thrown at backend/routes/history.py:60

async def import_generation(
    file: UploadFile = File(...),
    db: Session = Depends(get_db),
):
    """Import a generation from a ZIP archive."""
    MAX_FILE_SIZE = 50 * 1024 * 1024

    content = await file.read()

    if len(content) > MAX_FILE_SIZE:
        raise HTTPException(
            status_code=400, detail=f"File too large. Maximum size is {MAX_FILE_SIZE / (1024 * 1024)}MB"
        )

    try:
        result = await export_import.import_generation_from_zip(content, db)
        return result
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


@router.delete("/history/failed")
async def clear_failed_generations(db: Session = Depends(get_db)):
    """Delete every generation with status='failed'. Used by the UI's 'Clear failed' button (#410)."""
    count = await history.delete_failed_generations(db)
    return {"deleted": count}


@router.get("/history/{generation_id}", response_model=models.HistoryResponse)
async def get_generation(
    generation_id: str,
    db: Session = Depends(get_db),
):
    """Get a generation by ID."""
    result = (

View on GitHub (pinned to 51f49dea19)

Solutions

  1. Read the error message — ValueErrors here are user-facing and explain the specific ZIP problem.
  2. Only import ZIPs produced by GET /history/{id}/export for this app version.
  3. If the manifest schema changed across versions, re-export from the source version after upgrading.
  4. Open the ZIP locally and verify it contains the expected manifest + audio files before retrying.

Example fix

// before: upload any zip
upload(myZip);

// after: only export-produced zips
if (!file.name.endsWith('.voicebox.zip')) { alert('Use an exported generation ZIP'); return; }
upload(file);
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate it's an exported voicebox zip before uploading
if (!file.name.endsWith('.voicebox.zip')) { alert('Use an exported generation ZIP'); return; }
await upload(file);

Type guard

function looksLikeVoiceboxExport(file) {
  return file && typeof file.name === 'string' && file.name.endsWith('.voicebox.zip');
}

Try / catch

try {
  const res = await fetch('/history/import', { method:'POST', body: form });
  if (res.status === 400) {
    const d = await res.json();
    showImportError(d.detail); // carries the ValueError reason
    return;
  }
} catch (e) { console.error(e); }

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12). Data as JSON: /api/errors/0e0023ba713cf57b. Report an issue: GitHub.