jamiepine/voicebox · error · HTTPException
Generation not found
Error message
Generation not found
What it means
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.
Source
Thrown at backend/routes/generations.py:153
seed=data.seed,
normalize=data.normalize,
effects_chain=effects_chain_config,
instruct=data.instruct,
mode="generate",
max_chunk_chars=data.max_chunk_chars,
crossfade_ms=data.crossfade_ms,
)
)
return generation
@router.post("/generate/{generation_id}/retry", response_model=models.GenerationResponse)
async def retry_generation(generation_id: str, db: Session = Depends(get_db)):
"""Retry a failed generation using the same parameters."""
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") != "failed":
raise HTTPException(status_code=400, detail="Only failed generations can be retried")
gen.status = "generating"
gen.error = None
gen.audio_path = ""
gen.duration = 0
db.commit()
db.refresh(gen)
task_manager = get_task_manager()
task_manager.start_generation(
task_id=generation_id,
profile_id=gen.profile_id,
text=gen.text,
)
View on GitHub (pinned to 51f49dea19)
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.
Example fix
// before
await api.post(`/generate/${failedId}/retry`);
// after
const failed = await api.get('/history', { params: { status: 'failed' } });
if (!failed.items.some(g => g.id === failedId)) { removeCard(failedId); return; }
await api.post(`/generate/${failedId}/retry`); Defensive patterns
Strategy: validation
Validate before calling
gen = db.query(DBGeneration).filter_by(id=generation_id).first()
if gen is None:
raise GenerationMissing(generation_id) # would 404
# safe to POST /generate/{id}/retry Type guard
def generation_failed_and_exists(gen) -> bool:
return gen is not None and (gen.status or 'completed') == 'failed' Try / catch
try:
client.post(f'/generate/{generation_id}/retry')
except HTTPStatusError as e:
if e.response.status_code == 404:
remove_card(generation_id) # swept by clear-failed or deleted elsewhere
return
raise Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Source version not found
- Version not found
- Profile not found
- Only failed generations can be retried
- Story or generation not found
AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12).
Data as JSON: /api/errors/2d07b8c459900bde.
Report an issue: GitHub.