{"record":{"id":"03ae25f8d9cba72e","repo":"jamiepine/voicebox","slug":"generation-is-not-completed","errorCode":null,"errorMessage":"Generation is not completed","messagePattern":"Generation is not completed","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"backend/routes/effects.py","lineNumber":29,"sourceCode":"from .. import config, models\nfrom ..services import history\nfrom ..database import Generation as DBGeneration, get_db\n\nrouter = APIRouter()\n\n\n@router.post(\"/effects/preview/{generation_id}\")\nasync def preview_effects(\n    generation_id: str,\n    data: models.ApplyEffectsRequest,\n    db: Session = Depends(get_db),\n):\n    \"\"\"Apply effects to a generation's clean audio and stream back without saving.\"\"\"\n    gen = db.query(DBGeneration).filter_by(id=generation_id).first()\n    if not gen:\n        raise HTTPException(status_code=404, detail=\"Generation not found\")\n    if (gen.status or \"completed\") != \"completed\":\n        raise HTTPException(status_code=400, detail=\"Generation is not completed\")\n\n    from ..services import versions as versions_mod\n    from ..utils.effects import apply_effects, validate_effects_chain\n    from ..utils.audio import load_audio\n\n    chain_dicts = [e.model_dump() for e in data.effects_chain]\n    error = validate_effects_chain(chain_dicts)\n    if error:\n        raise HTTPException(status_code=400, detail=error)\n\n    all_versions = versions_mod.list_versions(generation_id, db)\n    clean_version = next((v for v in all_versions if v.effects_chain is None), None)\n    source_path = clean_version.audio_path if clean_version else gen.audio_path\n    resolved_source_path = config.resolve_storage_path(source_path)\n    if resolved_source_path is None or not resolved_source_path.exists():\n        raise HTTPException(status_code=404, detail=\"Source audio file not found\")\n\n    audio, sample_rate = await asyncio.to_thread(load_audio, str(resolved_source_path))","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/jamiepine/voicebox/blob/51f49dea198384b4eb6087b72c17057c6eb1c1cd/backend/routes/effects.py#L11-L47","documentation":"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.","triggerScenarios":"Requesting an effects preview against a generation that is still processing, has failed, or is in any non-completed state.","commonSituations":"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.","solutions":["Wait until the generation's status is 'completed' before enabling the preview action.","Poll or subscribe to generation status and only then call preview.","On 400 'Generation is not completed', re-check status and retry once it completes."],"exampleFix":"// before\nawait fetch(`/effects/preview/${genId}`, { method:'POST', body: JSON.stringify(payload) });\n// after\nconst gen = await fetch(`/generations/${genId}`).then(r => r.json());\nif (gen.status !== 'completed') { alert('Wait for generation to finish'); return; }\nawait fetch(`/effects/preview/${genId}`, { method:'POST', body: JSON.stringify(payload) });","handlingStrategy":"validation","validationCode":"const gen = await fetch(`/generations/${generationId}`).then(r => r.json());\nif ((gen.status ?? 'completed') !== 'completed') throw new Error('generation not completed');","typeGuard":"function isCompletedGeneration(g): g is { status: 'completed' } { return (g?.status ?? 'completed') === 'completed'; }","tryCatchPattern":"const r = await fetch(`/effects/preview/${id}`, { method:'POST', body: JSON.stringify(data) });\nif (r.status === 400) { const { detail } = await r.json(); /* 'Generation is not completed' or chain error */ }","preventionTips":["Only enable effects preview once status is 'completed'.","Poll/subscribe to generation status before acting.","Retry preview after the generation finishes."],"tags":["effects","http","validation","state","fastapi"],"backgroundTag":null,"analyzedSha":"51f49dea198384b4eb6087b72c17057c6eb1c1cd","analyzedAt":"2026-08-12T16:51:42.824Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}