jamiepine/voicebox · error · HTTPException
Version not found
Error message
Version not found
What it means
Returned as HTTP 404 by the set-default-version endpoint for /generations/{generation_id}/versions/{version_id}. The route fetches the version via versions.get_version(version_id) and additionally requires version.generation_id == generation_id. If the version does not exist, or it exists but belongs to a different generation, this 404 is raised. The mismatch check prevents cross-generation default promotion.
Source
Thrown at backend/routes/effects.py:236
return version
@router.put(
"/generations/{generation_id}/versions/{version_id}/set-default",
response_model=models.GenerationVersionResponse,
)
async def set_default_version(
generation_id: str,
version_id: str,
db: Session = Depends(get_db),
):
"""Set a specific version as the default for a generation."""
from ..services import versions as versions_mod
version = versions_mod.get_version(version_id, db)
if not version or version.generation_id != generation_id:
raise HTTPException(status_code=404, detail="Version not found")
result = versions_mod.set_default_version(version_id, db)
if not result:
raise HTTPException(status_code=404, detail="Version not found")
return result
@router.delete("/generations/{generation_id}/versions/{version_id}")
async def delete_generation_version(
generation_id: str,
version_id: str,
db: Session = Depends(get_db),
):
"""Delete a version. Cannot delete the last remaining version."""
from ..services import versions as versions_mod
version = versions_mod.get_version(version_id, db)
if not version or version.generation_id != generation_id:View on GitHub (pinned to 51f49dea19)
Solutions
- Source version_id and generation_id from a fresh GET /generations/{generation_id}/versions response.
- On 404, re-fetch the versions list and re-render the picker.
- Ensure the version's generation_id matches the path generation_id client-side before the call.
- Double-check URL template ordering: /generations/{generation_id}/versions/{version_id}.
Example fix
// before
api.post(`/generations/${genId}/versions/${cachedVersionId}/default`)
// after
const versions = await api.get(`/generations/${genId}/versions`);
const v = versions.find(x => x.id === cachedVersionId);
if (!v || v.generation_id !== genId) return;
api.post(`/generations/${genId}/versions/${v.id}/default`) Defensive patterns
Strategy: validation
Validate before calling
v = versions_mod.get_version(version_id, db)
if v is None or v.generation_id != generation_id:
raise VersionNotInGeneration(version_id, generation_id)
# safe to call set-default-version Type guard
def version_belongs_to_generation(version, generation_id: str) -> bool:
return version is not None and version.generation_id == generation_id Try / catch
try:
client.post(f'/generations/{gen_id}/versions/{ver_id}/default')
except HTTPStatusError as e:
if e.response.status_code == 404:
versions = client.get(f'/generations/{gen_id}/versions').json()
repopulate_picker(versions)
return
raise Prevention
- Source both ids from a fresh versions listing.
- Confirm v.generation_id === genId client-side before the call.
- On 404, re-fetch versions and rebuild the picker.
- Keep URL template argument order straight: /generations/{genId}/versions/{verId}.
When it happens
Trigger: Passing a version_id that does not exist; passing a version id from a different generation; the version was deleted between page load and the set-default call; swapping generation_id and version_id in the URL.
Common situations: Stale version list in the UI after a delete; user has multiple generations open and the wrong one's version is set as default; client reuses a cached version id after regeneration created new versions; URL path argument ordering mistake.
Related errors
- Source version not found
- Generation not found
- Cannot delete the last remaining version
- Profile not found
- Story or generation not found
AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12).
Data as JSON: /api/errors/a1949790584be15f.
Report an issue: GitHub.