{"record":{"id":"2d07b8c459900bde","repo":"jamiepine/voicebox","slug":"generation-not-found-2d07b8","errorCode":null,"errorMessage":"Generation not found","messagePattern":"Generation not found","errorType":"http","errorClass":"HTTPException","httpStatus":404,"severity":"error","filePath":"backend/routes/generations.py","lineNumber":153,"sourceCode":"            seed=data.seed,\n            normalize=data.normalize,\n            effects_chain=effects_chain_config,\n            instruct=data.instruct,\n            mode=\"generate\",\n            max_chunk_chars=data.max_chunk_chars,\n            crossfade_ms=data.crossfade_ms,\n        )\n    )\n\n    return generation\n\n\n@router.post(\"/generate/{generation_id}/retry\", response_model=models.GenerationResponse)\nasync def retry_generation(generation_id: str, db: Session = Depends(get_db)):\n    \"\"\"Retry a failed generation using the same parameters.\"\"\"\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\n    if (gen.status or \"completed\") != \"failed\":\n        raise HTTPException(status_code=400, detail=\"Only failed generations can be retried\")\n\n    gen.status = \"generating\"\n    gen.error = None\n    gen.audio_path = \"\"\n    gen.duration = 0\n    db.commit()\n    db.refresh(gen)\n\n    task_manager = get_task_manager()\n    task_manager.start_generation(\n        task_id=generation_id,\n        profile_id=gen.profile_id,\n        text=gen.text,\n    )\n","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/jamiepine/voicebox/blob/51f49dea198384b4eb6087b72c17057c6eb1c1cd/backend/routes/generations.py#L135-L171","documentation":"Returned as HTTP 404 by POST /generate/{generation_id}/retry. The route queries DBGeneration by id and raises this 404 when first() returns None. Retry only operates on an existing generation row that previously failed; without the row there is nothing to retry.","triggerScenarios":"POST /generate/{id}/retry with an id not in the Generation table; retrying a generation that was deleted (e.g. by 'clear failed'); passing a profile_id or version_id where a generation_id is expected.","commonSituations":"User clicks retry on a failed generation that was swept by 'clear failed'; stale UI after a history cleanup; id copied from a different environment; generation row never persisted because the initial create failed.","solutions":["Confirm the generation still exists via GET /history (with a failed-status filter) before offering retry.","On 404, remove the entry from the UI and stop offering retry.","Re-source the id from a fresh history listing rather than a cached value.","If the row is expected, check whether a cleanup job or another session deleted it."],"exampleFix":"// before\nawait api.post(`/generate/${failedId}/retry`);\n// after\nconst failed = await api.get('/history', { params: { status: 'failed' } });\nif (!failed.items.some(g => g.id === failedId)) { removeCard(failedId); return; }\nawait api.post(`/generate/${failedId}/retry`);","handlingStrategy":"validation","validationCode":"gen = db.query(DBGeneration).filter_by(id=generation_id).first()\nif gen is None:\n    raise GenerationMissing(generation_id)  # would 404\n# safe to POST /generate/{id}/retry","typeGuard":"def generation_failed_and_exists(gen) -> bool:\n    return gen is not None and (gen.status or 'completed') == 'failed'","tryCatchPattern":"try:\n    client.post(f'/generate/{generation_id}/retry')\nexcept HTTPStatusError as e:\n    if e.response.status_code == 404:\n        remove_card(generation_id)  # swept by clear-failed or deleted elsewhere\n        return\n    raise","preventionTips":["Source retryable ids from a fresh /history?status=failed listing.","On 404, remove the card from the UI rather than retrying blindly.","Avoid offering retry after a 'clear failed' action until the list refreshes.","Confirm the id is a generation id, not a version/profile id."],"tags":["fastapi","http-404","generate","retry","generations","not-found","rest"],"backgroundTag":null,"analyzedSha":"51f49dea198384b4eb6087b72c17057c6eb1c1cd","analyzedAt":"2026-08-12T16:51:42.824Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}