jamiepine/voicebox · error · HTTPException

Generation is not completed

Error message

Generation is not completed

What it means

HTTP 400 raised by POST /effects/preview/{generation_id} when the generation exists but its status is not 'completed'. The handler computes (gen.status or 'completed') and compares to 'completed', so a None status is treated as completed; any other status value (e.g. 'pending', 'failed', 'processing') triggers the error. Effects preview operates on the clean audio file, which only exists once generation finishes successfully.

Source

Thrown at backend/routes/effects.py:29

from .. import config, models
from ..services import history
from ..database import Generation as DBGeneration, get_db

router = APIRouter()


@router.post("/effects/preview/{generation_id}")
async def preview_effects(
    generation_id: str,
    data: models.ApplyEffectsRequest,
    db: Session = Depends(get_db),
):
    """Apply effects to a generation's clean audio and stream back without saving."""
    gen = db.query(DBGeneration).filter_by(id=generation_id).first()
    if not gen:
        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))

View on GitHub (pinned to 51f49dea19)

Solutions

  1. Wait until the generation's status is 'completed' before enabling the preview action.
  2. Poll or subscribe to generation status and only then call preview.
  3. On 400 'Generation is not completed', re-check status and retry once it completes.

Example fix

// before
await fetch(`/effects/preview/${genId}`, { method:'POST', body: JSON.stringify(payload) });
// after
const gen = await fetch(`/generations/${genId}`).then(r => r.json());
if (gen.status !== 'completed') { alert('Wait for generation to finish'); return; }
await fetch(`/effects/preview/${genId}`, { method:'POST', body: JSON.stringify(payload) });
Defensive patterns

Strategy: validation

Validate before calling

const gen = await fetch(`/generations/${generationId}`).then(r => r.json());
if ((gen.status ?? 'completed') !== 'completed') throw new Error('generation not completed');

Type guard

function isCompletedGeneration(g): g is { status: 'completed' } { return (g?.status ?? 'completed') === 'completed'; }

Try / catch

const r = await fetch(`/effects/preview/${id}`, { method:'POST', body: JSON.stringify(data) });
if (r.status === 400) { const { detail } = await r.json(); /* 'Generation is not completed' or chain error */ }

Prevention

When it happens

Trigger: Requesting an effects preview against a generation that is still processing, has failed, or is in any non-completed state.

Common situations: User clicks 'preview effects' before the generation finishes; polling the generation list and acting on a row whose status is 'processing'; previewing a generation that failed and was never re-run.

Related errors


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