{"record":{"id":"ed49739b30c0bbab","repo":"jamiepine/voicebox","slug":"invalid-manifest-json-missing-profile","errorCode":null,"errorMessage":"Invalid manifest.json: missing profile","messagePattern":"Invalid manifest\\.json: missing profile","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"backend/services/export_import.py","lineNumber":157,"sourceCode":"    try:\n        with zipfile.ZipFile(zip_buffer, 'r') as zip_file:\n            # Validate ZIP structure\n            namelist = zip_file.namelist()\n            \n            if \"manifest.json\" not in namelist:\n                raise ValueError(\"ZIP archive missing manifest.json\")\n            \n            if \"samples.json\" not in namelist:\n                raise ValueError(\"ZIP archive missing samples.json\")\n            \n            # Read manifest\n            manifest_data = json.loads(zip_file.read(\"manifest.json\"))\n            \n            if \"version\" not in manifest_data:\n                raise ValueError(\"Invalid manifest.json: missing version\")\n            \n            if \"profile\" not in manifest_data:\n                raise ValueError(\"Invalid manifest.json: missing profile\")\n            \n            profile_data = manifest_data[\"profile\"]\n            \n            # Read samples mapping\n            samples_data = json.loads(zip_file.read(\"samples.json\"))\n            \n            if not isinstance(samples_data, dict):\n                raise ValueError(\"Invalid samples.json: must be a dictionary\")\n            \n            # Get unique profile name\n            original_name = profile_data.get(\"name\", \"Imported Profile\")\n            unique_name = _get_unique_profile_name(original_name, db)\n            \n            # Create profile\n            profile_create = VoiceProfileCreate(\n                name=unique_name,\n                description=profile_data.get(\"description\"),\n                language=profile_data.get(\"language\", \"en\"),","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/jamiepine/voicebox/blob/51f49dea198384b4eb6087b72c17057c6eb1c1cd/backend/services/export_import.py#L139-L175","documentation":"manifest.json must contain a 'profile' object (name/description/language). The importer reads profile_data = manifest_data['profile'] and uses it to build VoiceProfileCreate. Missing 'profile' is rejected before any DB write.","triggerScenarios":"Manifest edited to remove the profile block; a manifest from an unrelated feature uploaded to the profile-import endpoint; cross-endpoint confusion.","commonSituations":"Hand-editing the manifest; uploading a generation-export archive (which uses a different top-level shape) to profile import.","solutions":["Re-export the profile to regenerate a valid manifest.","If manual, include profile: {name, description, language}.","Verify you're hitting the profile-import endpoint, not generation-import."],"exampleFix":"// before\n{\"version\": \"1.0\", \"has_avatar\": false}\n\n// after\n{\"version\": \"1.0\", \"profile\": {\"name\": \"My Voice\", \"description\": \"...\", \"language\": \"en\"}, \"has_avatar\": false}","handlingStrategy":"validation","validationCode":"import io, json, zipfile\n\ndef manifest_has_profile(file_bytes) -> bool:\n    with zipfile.ZipFile(io.BytesIO(file_bytes)) as z:\n        return \"profile\" in json.loads(z.read(\"manifest.json\"))","typeGuard":"def has_profile_block(m) -> bool:\n    return isinstance(m, dict) and isinstance(m.get(\"profile\"), dict)","tryCatchPattern":"try:\n    await import_profile_from_zip(file_bytes, db)\nexcept ValueError as e:\n    if \"missing profile\" in str(e):\n        # not a profile archive; don't treat as a generic import error\n        ...\n    raise","preventionTips":["Validate manifest.profile is a dict before importing.","Use exporter output as the canonical archive format."],"tags":["profiles","import","manifest","validation","schema"],"backgroundTag":null,"analyzedSha":"51f49dea198384b4eb6087b72c17057c6eb1c1cd","analyzedAt":"2026-08-12T16:51:42.824Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}