{"record":{"id":"a9639b7c42c75e50","repo":"jamiepine/voicebox","slug":"audio-file-not-found-sample-audio-path","errorCode":null,"errorMessage":"Audio file not found: {sample.audio_path}","messagePattern":"Audio file not found: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"backend/services/export_import.py","lineNumber":103,"sourceCode":"            \"version\": \"1.0\",\n            \"profile\": {\n                \"name\": profile.name,\n                \"description\": profile.description,\n                \"language\": profile.language,\n            },\n            \"has_avatar\": has_avatar,\n        }\n        zip_file.writestr(\"manifest.json\", json.dumps(manifest, indent=2))\n\n        # Create samples.json mapping\n        samples_data = {}\n        profile_dir = config.get_profiles_dir() / profile_id\n\n        for sample in samples:\n            # Get filename from audio_path (should be {sample_id}.wav)\n            audio_path = config.resolve_storage_path(sample.audio_path)\n            if audio_path is None:\n                raise ValueError(f\"Audio file not found: {sample.audio_path}\")\n            filename = audio_path.name\n\n            # Read audio file\n            if not audio_path.exists():\n                raise ValueError(f\"Audio file not found: {audio_path}\")\n\n            # Add to samples directory in ZIP\n            zip_path = f\"samples/{filename}\"\n            zip_file.write(audio_path, zip_path)\n\n            # Map filename to reference text\n            samples_data[filename] = sample.reference_text\n\n        zip_file.writestr(\"samples.json\", json.dumps(samples_data, indent=2))\n    \n    zip_buffer.seek(0)\n    return zip_buffer.read()\n","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/jamiepine/voicebox/blob/51f49dea198384b4eb6087b72c17057c6eb1c1cd/backend/services/export_import.py#L85-L121","documentation":"For each sample, export calls config.resolve_storage_path(sample.audio_path); if it returns None (the stored relative path can't be mapped under the configured storage root), export raises ValueError using the stored audio_path string. This catches corrupt rows whose audio_path is inconsistent with the current storage layout.","triggerScenarios":"Storage root config changed since the sample was created (different DATA_DIR/profiles dir); audio_path stored as an absolute or stray path that resolve_storage_path rejects; sample row pointing outside the allowed storage root.","commonSituations":"Data directory moved; DB migrated without migrating storage paths; manual DB edit inserting a bad path.","solutions":["Confirm the configured storage root (config.get_data_dir / get_profiles_dir) matches where sample files actually live.","Inspect sample.audio_path — it should be a relative path under the storage root.","Relink the audio files or fix the stored paths in the DB."],"exampleFix":"# before\naudio_path = config.resolve_storage_path(sample.audio_path)\nif audio_path is None:\n    raise ValueError(f\"Audio file not found: {sample.audio_path}\")\n\n# after — log resolved root + offending path for diagnosis\naudio_path = config.resolve_storage_path(sample.audio_path)\nif audio_path is None:\n    logger.error(\"unresolvable %r under %s\", sample.audio_path, config.get_profiles_dir())\n    raise ValueError(f\"Audio file not found: {sample.audio_path}\")","handlingStrategy":"validation","validationCode":"from backend import config\nfrom backend.database import ProfileSample as DBProfileSample\n\ndef all_samples_resolvable(profile_id, db) -> bool:\n    for s in db.query(DBProfileSample).filter_by(profile_id=profile_id):\n        if config.resolve_storage_path(s.audio_path) is None:\n            return False\n    return True","typeGuard":null,"tryCatchPattern":"try:\n    data = export_profile_to_zip(pid, db)\nexcept ValueError as e:\n    if str(e).startswith(\"Audio file not found\"):\n        # data-integrity issue; surface for repair\n        ...\n    raise","preventionTips":["Never store absolute paths in audio_path; keep them relative to the storage root.","Run a storage-path audit after moving the data directory.","Validate resolve_storage_path round-trips before inserting sample rows."],"tags":["profiles","export","storage","path","data-integrity"],"backgroundTag":null,"analyzedSha":"51f49dea198384b4eb6087b72c17057c6eb1c1cd","analyzedAt":"2026-08-12T16:51:42.824Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}