{"record":{"id":"7c25028d0a2c8a19","repo":"jamiepine/voicebox","slug":"invalid-zip-file","errorCode":null,"errorMessage":"Invalid ZIP file","messagePattern":"Invalid ZIP file","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"backend/services/export_import.py","lineNumber":236,"sourceCode":"                    tmp.write(zip_file.read(zip_path))\n                    tmp_path = tmp.name\n                \n                try:\n                    # Add sample to profile\n                    await add_profile_sample(\n                        profile.id,\n                        tmp_path,\n                        reference_text,\n                        db,\n                    )\n                finally:\n                    # Clean up temp file\n                    Path(tmp_path).unlink(missing_ok=True)\n            \n            return profile\n            \n    except zipfile.BadZipFile:\n        raise ValueError(\"Invalid ZIP file\")\n    except json.JSONDecodeError as e:\n        raise ValueError(f\"Invalid JSON in archive: {e}\")\n    except Exception as e:\n        if isinstance(e, ValueError):\n            raise\n        raise ValueError(f\"Error importing profile: {str(e)}\")\n\n\ndef export_generation_to_zip(generation_id: str, db: Session) -> bytes:\n    \"\"\"\n    Export a generation to a ZIP archive.\n    \n    Args:\n        generation_id: Generation ID to export\n        db: Database session\n        \n    Returns:\n        ZIP file contents as bytes","sourceCodeStart":218,"sourceCodeEnd":254,"githubUrl":"https://github.com/jamiepine/voicebox/blob/51f49dea198384b4eb6087b72c17057c6eb1c1cd/backend/services/export_import.py#L218-L254","documentation":"Raised by the profile import path when Python's zipfile module emits zipfile.BadZipFile while opening the uploaded bytes (export_import.py:235). The bytes are not a valid ZIP container — truncated, wrong format, or zero-length. The handler normalizes the low-level BadZipFile into a ValueError(\"Invalid ZIP file\") so callers see a single error type.","triggerScenarios":"Call to the profile import function with file_bytes that fails zipfile.ZipFile(BytesIO(file_bytes), 'r'). Happens when a user uploads a .tar/.gz, a raw WAV, an HTML error page from a failed download, or a file that was cut off mid-transfer.","commonSituations":"Browser sent the wrong file due to a renamed extension; a proxy/CDN returned an HTML error page with a .zip content-type; the file was chunked and the last chunk was dropped; the user is uploading a generations ZIP into the profile-import endpoint.","solutions":["Verify the file magic bytes locally before upload: the first four bytes of a ZIP are b'PK\\x03\\x04'.","Ensure the client sends the exact bytes produced by export_profile_to_zip without re-encoding (no base64, no form-wrapping unless the endpoint expects it).","Re-export the profile on the source instance and retry; if it still fails, the export itself is the bug.","Confirm you are hitting the profile import endpoint, not the generation import endpoint — they expect different manifests."],"exampleFix":"// before (js client): sending a tarball\nconst body = new FormData(); body.append('file', tarballFile);\n// after: validate magic bytes before sending\nconst buf = new Uint8Array(await file.arrayBuffer());\nconst isZip = buf[0]===0x50 && buf[1]===0x4b && buf[2]===0x03 && buf[3]===0x04;\nif (!isZip) throw new Error('not a zip');\nbody.append('file', file);","handlingStrategy":"validation","validationCode":"import zipfile\n\ndef is_valid_zip(file_bytes: bytes) -> bool:\n    if len(file_bytes) < 4 or file_bytes[:4] != b'PK\\x03\\x04':\n        return False\n    try:\n        with zipfile.ZipFile(io.BytesIO(file_bytes), 'r') as z:\n            return z.testzip() is None\n    except zipfile.BadZipFile:\n        return False\n\n# before calling import_profile_from_bytes:\nif not is_valid_zip(file_bytes):\n    raise HTTPException(400, 'Please upload a valid .zip produced by the exporter.')","typeGuard":"null","tryCatchPattern":"try:\n    profile = await import_profile_from_bytes(file_bytes, db)\nexcept ValueError as e:\n    if str(e) == 'Invalid ZIP file':\n        raise HTTPException(400, 'The uploaded file is not a valid ZIP archive.')\n    raise HTTPException(400, str(e))","preventionTips":["Validate the PK\\x03\\x04 magic bytes on the client before uploading.","Always source import files from export_profile_to_zip on a matching version.","Set the form input accept='.zip' so the OS file picker filters out non-zips."],"tags":["zip","import","validation","file-upload"],"backgroundTag":null,"analyzedSha":"51f49dea198384b4eb6087b72c17057c6eb1c1cd","analyzedAt":"2026-08-12T16:51:42.824Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}