jamiepine/voicebox · error · HTTPException

Generation failed; no audio available

Error message

Generation failed; no audio available

What it means

Returned as a 404 from GET /audio/{generation_id} when a generation record exists, its status is 'failed', and there is no playable audio artifact on disk (resolve_storage_path returned None or the path is not a regular file). The handler deliberately distinguishes a failed generation from a missing file so the frontend can show 'generation failed' rather than a generic 404. It is a data-state error, not a code bug.

Source

Thrown at backend/routes/audio.py:61

        filename=f"generation_{version.generation_id}_{version.label}{audio_path.suffix}",
    )


@router.get("/audio/{generation_id}")
async def get_audio(generation_id: str, db: Session = Depends(get_db)):
    """Serve generated audio file (serves the default version)."""
    generation = await history.get_generation(generation_id, db)
    if not generation:
        raise HTTPException(status_code=404, detail="Generation not found")

    audio_path = config.resolve_storage_path(generation.audio_path)
    if audio_path is None or not audio_path.is_file():
        detail = (
            "Generation failed; no audio available"
            if generation.status == "failed"
            else "Audio file not found"
        )
        raise HTTPException(status_code=404, detail=detail)

    return FileResponse(
        audio_path,
        media_type=_audio_media_type(audio_path),
        filename=f"generation_{generation_id}{audio_path.suffix}",
    )


@router.get("/samples/{sample_id}")
async def get_sample_audio(sample_id: str, db: Session = Depends(get_db)):
    """Serve profile sample audio file."""
    from ..database import ProfileSample as DBProfileSample

    sample = db.query(DBProfileSample).filter_by(id=sample_id).first()
    if not sample:
        raise HTTPException(status_code=404, detail="Sample not found")

    audio_path = config.resolve_storage_path(sample.audio_path)

View on GitHub (pinned to 51f49dea19)

Solutions

  1. Inspect the generation row's status and error fields: if status is 'failed', surface the upstream failure reason to the user instead of retrying the audio fetch.
  2. Verify config.resolve_storage_path(generation.audio_path) returns a real path and that STORAGE_DIR matches where jobs actually write output.
  3. If failed rows are stale, delete or re-run the generation so it produces a fresh audio_path.
  4. Guard the frontend: when generation status is 'failed', show the failure UI and do not request the audio stream.

Example fix

// before
const audio = await fetch(`/audio/${id}`); // 404 on failed gens
// after
const gen = await getGeneration(id);
if (gen.status === 'failed') {
  showError(gen.error || 'Generation failed');
} else {
  const audio = await fetch(`/audio/${id}`);
}
Defensive patterns

Strategy: validation

Validate before calling

// Before requesting audio, check the generation status from the generation detail endpoint.
const gen = await getGeneration(generationId);
if (gen.status === 'failed') {
  // do not fetch /audio/{id}; show the failure instead
  throw new Error('Generation failed; audio will not be available');
}

Type guard

type GenerationState = 'pending' | 'completed' | 'failed';
function isAudioAvailable(gen: { status: GenerationState; audio_path: string | null }): boolean {
  return gen.status === 'completed' && !!gen.audio_path;
}

Try / catch

try {
  const r = await fetch(`/audio/${id}`);
  if (r.status === 404) {
    const body = await r.json();
    if (body.detail === 'Generation failed; no audio available') {
      showFailureUI();
    } else {
      showMissingFileUI();
    }
    return;
  }
  play(await r.blob());
} catch (e) {
  showNetworkError(e);
}

Prevention

When it happens

Trigger: GET /audio/{generation_id} where the generation row has status=='failed' and generation.audio_path is null, empty, outside the configured storage root, or points to a non-existent/non-regular file. Happens after a TTS/voice-clone job that errored before writing audio.

Common situations: The TTS engine or model download crashed mid-generation; the worker marked status failed but never wrote the file. Or storage was migrated/cleaned and stale failed rows remain. Or config.resolve_storage_path rejects the stored relative path after a STORAGE_DIR change.

Related errors


AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12). Data as JSON: /api/errors/7145047b81684cf3. Report an issue: GitHub.