{"record":{"id":"724f3b6896f3608f","repo":"jamiepine/voicebox","slug":"invalid-sample-filename-filename-must-be-wav","errorCode":null,"errorMessage":"Invalid sample filename: {filename} (must be .wav)","messagePattern":"Invalid sample filename: (.+?) \\(must be \\.wav\\)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"backend/services/export_import.py","lineNumber":207,"sourceCode":"                    # Extract to temporary file\n                    import tempfile\n                    with tempfile.NamedTemporaryFile(suffix=Path(avatar_file).suffix, delete=False) as tmp:\n                        tmp.write(zip_file.read(avatar_file))\n                        tmp_path = tmp.name\n\n                    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,","sourceCodeStart":189,"sourceCodeEnd":225,"githubUrl":"https://github.com/jamiepine/voicebox/blob/51f49dea198384b4eb6087b72c17057c6eb1c1cd/backend/services/export_import.py#L189-L225","documentation":"Each key in samples.json must end with '.wav' (case-sensitive endswith check). The importer extracts each referenced file to a temp .wav and passes it to add_profile_sample; a non-wav key is rejected before extraction.","triggerScenarios":"samples.json contains a .mp3/.flac/.txt key or an extensionless key; case mismatch such as '.WAV' (uppercase) failing the case-sensitive endswith('.wav') check.","commonSituations":"Mixing audio formats in a hand-built archive; uppercase extension coming from a case-insensitive filesystem export (macOS/Windows).","solutions":["Convert source audio to .wav and re-export.","If only the extension differs, rename keys (and the matching zip entries) to lowercase .wav.","Ensure the exporter only ever emits .wav."],"exampleFix":"// before\n{\"clip.mp3\": \"hello\"}\n\n// after\n{\"clip.wav\": \"hello\"}","handlingStrategy":"validation","validationCode":"import io, json, zipfile\n\ndef all_keys_wav(file_bytes) -> bool:\n    with zipfile.ZipFile(io.BytesIO(file_bytes)) as z:\n        return all(k.endswith(\".wav\") for k in json.loads(z.read(\"samples.json\")))","typeGuard":"def is_wav_filename(name) -> bool:\n    return isinstance(name, str) and name.lower().endswith(\".wav\")","tryCatchPattern":"try:\n    await import_profile_from_zip(file_bytes, db)\nexcept ValueError as e:\n    if \"must be .wav\" in str(e):\n        # convert audio to wav, rename keys + zip entries, retry\n        ...\n    raise","preventionTips":["Normalize all imported audio to .wav before zipping.","Watch for uppercase .WAV on macOS/Windows exports — normalize to lowercase."],"tags":["profiles","import","samples","validation","audio-format"],"backgroundTag":null,"analyzedSha":"51f49dea198384b4eb6087b72c17057c6eb1c1cd","analyzedAt":"2026-08-12T16:51:42.824Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}