jamiepine/voicebox · error · HTTPException

Source audio file not found

Error message

Source audio file not found

What it means

HTTP 404 raised by POST /effects/preview/{generation_id} when the source audio file cannot be located on disk. The handler resolves the path via config.resolve_storage_path(source_path) (falling back to gen.audio_path when no clean version exists) and raises 404 when resolution returns None or the resolved file does not exist. The generation record exists and is completed, but the underlying audio artifact is missing from storage.

Source

Thrown at backend/routes/effects.py:45

        raise HTTPException(status_code=404, detail="Generation not found")
    if (gen.status or "completed") != "completed":
        raise HTTPException(status_code=400, detail="Generation is not completed")

    from ..services import versions as versions_mod
    from ..utils.effects import apply_effects, validate_effects_chain
    from ..utils.audio import load_audio

    chain_dicts = [e.model_dump() for e in data.effects_chain]
    error = validate_effects_chain(chain_dicts)
    if error:
        raise HTTPException(status_code=400, detail=error)

    all_versions = versions_mod.list_versions(generation_id, db)
    clean_version = next((v for v in all_versions if v.effects_chain is None), None)
    source_path = clean_version.audio_path if clean_version else gen.audio_path
    resolved_source_path = config.resolve_storage_path(source_path)
    if resolved_source_path is None or not resolved_source_path.exists():
        raise HTTPException(status_code=404, detail="Source audio file not found")

    audio, sample_rate = await asyncio.to_thread(load_audio, str(resolved_source_path))
    processed = await asyncio.to_thread(apply_effects, audio, sample_rate, chain_dicts)

    import soundfile as sf

    buf = io.BytesIO()
    await asyncio.to_thread(lambda: sf.write(buf, processed, sample_rate, format="WAV"))
    buf.seek(0)

    return StreamingResponse(
        buf,
        media_type="audio/wav",
        headers={
            "Content-Disposition": f'inline; filename="preview_{generation_id}.wav"',
            "Cache-Control": "no-cache, no-store",
        },
    )

View on GitHub (pinned to 51f49dea19)

Solutions

  1. Verify the storage/data directory configured for the backend contains the generated audio files.
  2. If you migrated storage, re-run resolve_storage_path checks or regenerate the audio.
  3. Re-run the generation to reproduce the audio file, then retry the preview.
  4. Confirm config.resolve_storage_path returns a real path for the stored audio_path value.

Example fix

# before
resolved = config.resolve_storage_path(source_path)
# after
resolved = config.resolve_storage_path(source_path)
if resolved is None or not resolved.exists():
    logger.error('missing audio for generation %s at %s', generation_id, source_path)
    # regenerate or restore from backup before previewing
Defensive patterns

Strategy: try-catch

Validate before calling

import config
resolved = config.resolve_storage_path(source_path)
if resolved is None or not resolved.exists():
    raise RuntimeError('source audio missing on disk')

Try / catch

const r = await fetch(`/effects/preview/${id}`, { method:'POST', body: JSON.stringify(data) });
if (r.status === 404 && (await r.json()).detail === 'Source audio file not found') { /* regenerate or restore storage */ }

Prevention

When it happens

Trigger: The generation row is present and completed, but the audio file was deleted, moved, or never written (storage misconfiguration, partial migration, manual cleanup of the data dir).

Common situations: Storage directory relocated without updating config; data dir pruned by an external script; file write failed silently during generation; path stored as absolute and the host changed.

Related errors


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