jamiepine/voicebox · warning · HTTPException

File too large. Maximum size is {MAX_FILE_SIZE / (1024 * 102

Error message

File too large. Maximum size is {MAX_FILE_SIZE / (1024 * 1024)}MB

What it means

400 from POST /profiles/import. The endpoint reads the entire uploaded ZIP into memory (content = await file.read()) and rejects it if len(content) > MAX_FILE_SIZE where MAX_FILE_SIZE = 100 * 1024 * 1024 (100 MiB). The check happens after the full read, so the upload completes before the rejection — there's no streaming/chunked size guard at this layer.

Source

Thrown at backend/routes/profiles.py:56

@router.get("/profiles", response_model=list[models.VoiceProfileResponse])
async def list_profiles(db: Session = Depends(get_db)):
    """List all voice profiles."""
    return await profiles.list_profiles(db)


@router.post("/profiles/import", response_model=models.VoiceProfileResponse)
async def import_profile(
    file: UploadFile = File(...),
    db: Session = Depends(get_db),
):
    """Import a voice profile from a ZIP archive."""
    MAX_FILE_SIZE = 100 * 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:
        profile = await export_import.import_profile_from_zip(content, db)
        return profile
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


# ── Preset Voice Endpoints ───────────────────────────────────────────
# These MUST be declared before /profiles/{profile_id} to avoid the
# wildcard swallowing "presets" as a profile_id.


@router.get("/profiles/presets/{engine}")

View on GitHub (pinned to 51f49dea19)

Solutions

  1. Reduce the archive below 100 MiB: remove unused samples, downsample/trim long clips, or re-export as a tighter archive.
  2. Split a large multi-profile set into separate single-profile ZIPs and import each.
  3. Confirm you're uploading a Voicebox profile export, not a generic backup.
  4. If you genuinely need larger imports, raise MAX_FILE_SIZE server-side (and ensure reverse-proxy body limits — nginx client_max_body_size, etc. — are raised to match).

Example fix

# before
POST /profiles/import  with 180MB voicebox.zip  -> 400
# after
zip -9 voicebox.zip profile.json samples/   # recompress / trim to <100MB
POST /profiles/import  with voicebox.zip
Defensive patterns

Strategy: validation

Validate before calling

const MAX_PROFILE_IMPORT_BYTES = 100 * 1024 * 1024;
async function importProfile(file: File) {
  if (file.size > MAX_PROFILE_IMPORT_BYTES) {
    throw new Error(`File too large (${(file.size/1048576).toFixed(1)}MB). Max is 100MB.`);
  }
  const form = new FormData();
  form.append('file', file);
  return await fetch('/profiles/import', {method:'POST', body: form});
}

Try / catch

try {
  await importProfile(file);
} catch (e) {
  if (e.response?.status === 400 && /File too large/i.test(e.response.detail)) {
    // prompt user to trim the archive / split profiles
  } else throw e;
}

Prevention

When it happens

Trigger: POST /profiles/import (multipart form field 'file') with a ZIP larger than 100 MiB; a profile whose cloned-voice samples were bundled into a very large archive; accidentally attaching an uncompressed export or the wrong file (e.g. a full backup dump).

Common situations: Profile with many long reference-audio samples; uncompressed ZIP (samples are already compressed audio, so ZIP gives little gain); user attached the whole data/ directory export by mistake; export from a system with higher per-profile sample limits imported on one with the 100 MiB cap.

Related errors


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