jamiepine/voicebox · warning · HTTPException
Generation has no audio file
Error message
Generation has no audio file
What it means
Returned by GET /history/{generation_id}/export-audio when the generation row exists but `generation.audio_path` is falsy (None or empty string). This means the row was created without an audio file — e.g. a failed generation that never produced output, or an imported non-audio row. HTTP 404.
Source
Thrown at backend/routes/history.py:176
return StreamingResponse(
io.BytesIO(zip_bytes),
media_type="application/zip",
headers={"Content-Disposition": safe_content_disposition("attachment", filename)},
)
@router.get("/history/{generation_id}/export-audio")
async def export_generation_audio(
generation_id: str,
db: Session = Depends(get_db),
):
"""Export only the audio file from a generation."""
generation = db.query(DBGeneration).filter_by(id=generation_id).first()
if not generation:
raise HTTPException(status_code=404, detail="Generation not found")
if not generation.audio_path:
raise HTTPException(status_code=404, detail="Generation has no audio file")
audio_path = config.resolve_storage_path(generation.audio_path)
if audio_path is None or not audio_path.is_file():
raise HTTPException(status_code=404, detail="Audio file not found")
safe_text = "".join(c for c in generation.text[:30] if c.isalnum() or c in (" ", "-", "_")).strip()
if not safe_text:
safe_text = "generation"
# Append a short id so exports of similarly-worded generations don't collide
# on the same filename (the first 30 chars are frequently identical).
filename = f"{safe_text}-{generation_id[:8]}.wav"
return FileResponse(
audio_path,
media_type="audio/wav",
headers={"Content-Disposition": safe_content_disposition("attachment", filename)},
)
View on GitHub (pinned to 51f49dea19)
Solutions
- Hide/disable the audio-export action unless the generation has a non-empty audio_path and a terminal status.
- On 404 'Generation has no audio file.', show a user-facing message rather than retrying.
- Filter the history list so rows without audio_path can't trigger this endpoint.
Example fix
// before
<button onClick={() => downloadAudio(id)}>Download</button>
// after
<button disabled={!row.audio_path || !['completed'].includes(row.status)}
onClick={() => downloadAudio(id)}>Download</button> Defensive patterns
Strategy: validation
Validate before calling
if (!row.audio_path) { /* hide audio-export action */ return; }
if (!['completed'].includes(row.status)) { /* not ready */ return; }
await fetch(`/history/${id}/export-audio`); Type guard
function hasAudioPath(row) {
return row != null && typeof row.audio_path === 'string' && row.audio_path.length > 0;
} Try / catch
try {
const res = await fetch(`/history/${id}/export-audio`);
if (res.status === 404) {
const d = await res.json();
if (/no audio file/i.test(d.detail)) { alert('No audio for this generation'); return; }
}
} catch (e) { console.error(e); } Prevention
- Disable the audio-export action when audio_path is empty or status isn't completed.
- Don't offer the action on failed/in-progress rows.
When it happens
Trigger: Exporting audio for a generation whose status is 'failed' (no audio written); a row created for metadata-only purposes; a generation still in progress (loading_model/generating) that hasn't written audio yet.
Common situations: User clicks 'download audio' on a failed or in-progress generation; legacy rows from before audio_path was populated.
Related errors
- Audio file not found
- Generation failed; no audio available
- Sample not found
- Audio file not found
- {exception message from set_channel_voices (ValueError)}
AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12).
Data as JSON: /api/errors/3d7da069d37d20fd.
Report an issue: GitHub.