jamiepine/voicebox · error · ValueError

ZIP archive missing manifest.json

Error message

ZIP archive missing manifest.json

What it means

import_profile_from_zip() requires a manifest.json entry at the ZIP root. If zip_file.namelist() lacks it, the import is rejected before any parsing. manifest.json carries the version/profile metadata required to reconstruct the profile.

Source

Thrown at backend/services/export_import.py:145

    Args:
        file_bytes: ZIP file contents
        db: Database session
        
    Returns:
        Created profile
        
    Raises:
        ValueError: If ZIP is invalid or missing required files
    """
    zip_buffer = io.BytesIO(file_bytes)
    
    try:
        with zipfile.ZipFile(zip_buffer, 'r') as zip_file:
            # Validate ZIP structure
            namelist = zip_file.namelist()
            
            if "manifest.json" not in namelist:
                raise ValueError("ZIP archive missing manifest.json")
            
            if "samples.json" not in namelist:
                raise ValueError("ZIP archive missing samples.json")
            
            # Read manifest
            manifest_data = json.loads(zip_file.read("manifest.json"))
            
            if "version" not in manifest_data:
                raise ValueError("Invalid manifest.json: missing version")
            
            if "profile" not in manifest_data:
                raise ValueError("Invalid manifest.json: missing profile")
            
            profile_data = manifest_data["profile"]
            
            # Read samples mapping
            samples_data = json.loads(zip_file.read("samples.json"))
            

View on GitHub (pinned to 51f49dea19)

Solutions

  1. Only import ZIPs produced by the profile-export flow.
  2. If migrating from another tool, write a converter that emits manifest.json + samples.json in the expected layout.
  3. Confirm the file is a profile export, not a generation export.

Example fix

# before — arbitrary zip of wavs
await import_profile_from_zip(arbitrary_zip_bytes, db)

# after — produce a profile archive first
exported = export_profile_to_zip(pid, src_db)
await import_profile_from_zip(exported, dst_db)
Defensive patterns

Strategy: validation

Validate before calling

import io, zipfile

def has_manifest(file_bytes) -> bool:
    with zipfile.ZipFile(io.BytesIO(file_bytes)) as z:
        return "manifest.json" in z.namelist()

Try / catch

try:
    await import_profile_from_zip(file_bytes, db)
except ValueError as e:
    if "missing manifest.json" in str(e):
        # reject upload with a clear 'use Export to produce the archive' message
        ...
    raise

Prevention

When it happens

Trigger: Uploading a ZIP that wasn't produced by export_profile_to_zip — a random zip, a hand-rolled archive, or a generation-export ZIP (different manifest shape) aimed at the profile-import endpoint.

Common situations: User zips a folder of wavs instead of using Export; cross-endpoint confusion (generation import vs profile import); third-party archive.

Related errors


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