{"record":{"id":"f6f324920830306d","repo":"jamiepine/voicebox","slug":"sample-file-not-found-in-zip-zip-path","errorCode":null,"errorMessage":"Sample file not found in ZIP: {zip_path}","messagePattern":"Sample file not found in ZIP: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"backend/services/export_import.py","lineNumber":213,"sourceCode":"                    try:\n                        from .profiles import upload_avatar\n                        await upload_avatar(profile.id, tmp_path, db)\n                    finally:\n                        Path(tmp_path).unlink(missing_ok=True)\n                except Exception as e:\n                    # Avatar import is optional - continue even if it fails\n                    pass\n\n            for filename, reference_text in samples_data.items():\n                # Validate filename\n                if not filename.endswith('.wav'):\n                    raise ValueError(f\"Invalid sample filename: {filename} (must be .wav)\")\n                \n                # Extract audio file to temp location\n                zip_path = f\"samples/{filename}\"\n                \n                if zip_path not in namelist:\n                    raise ValueError(f\"Sample file not found in ZIP: {zip_path}\")\n                \n                # Extract to temporary file\n                import tempfile\n                with tempfile.NamedTemporaryFile(suffix=\".wav\", delete=False) as tmp:\n                    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)","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/jamiepine/voicebox/blob/51f49dea198384b4eb6087b72c17057c6eb1c1cd/backend/services/export_import.py#L195-L231","documentation":"For each filename key in samples.json the importer expects a matching samples/{filename} entry in the ZIP namelist. If it's absent the importer raises rather than silently skipping referenced audio. The path is built with a forward slash: f\"samples/{filename}\".","triggerScenarios":"samples.json references 'abc.wav' but the archive contains 'samples/ABC.wav' (case mismatch), the audio entry was never added, or backslash separators from a Windows-built zip don't match the forward-slash lookup.","commonSituations":"Hand-edited samples.json not matching zip contents; case-sensitivity crossing OSes (Linux import of a Windows-built zip); partial zip assembly.","solutions":["Re-export so samples.json and the audio entries stay consistent.","Check case and path separators — namelist uses forward slashes; rebuild on the same OS if needed.","Remove orphan keys from samples.json or add the missing audio entries."],"exampleFix":"# before — samples.json says 'abc.wav' but the zip has 'samples/ABC.wav'\n# after — keep names consistent: lowercase keys, matching 'samples/<name>' entries, forward slashes","handlingStrategy":"validation","validationCode":"import io, json, zipfile\n\ndef samples_match_entries(file_bytes) -> bool:\n    with zipfile.ZipFile(io.BytesIO(file_bytes)) as z:\n        names = set(z.namelist())\n        return all(f\"samples/{k}\" in names for k in json.loads(z.read(\"samples.json\")))","typeGuard":null,"tryCatchPattern":"try:\n    await import_profile_from_zip(file_bytes, db)\nexcept ValueError as e:\n    if \"Sample file not found in ZIP\" in str(e):\n        # reconcile samples.json keys with archive entries (case/separators)\n        ...\n    raise","preventionTips":["Only import archives from the official exporter.","On case-sensitive filesystems (Linux) keep filenames lowercase and stable.","Validate that every samples.json key has a matching samples/<key> entry before import."],"tags":["profiles","import","samples","zip","validation"],"backgroundTag":null,"analyzedSha":"51f49dea198384b4eb6087b72c17057c6eb1c1cd","analyzedAt":"2026-08-12T16:51:42.824Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}