jamiepine/voicebox · error · HTTPException
Story or generation not found
Error message
Story or generation not found
What it means
Returned by POST /stories/{story_id}/items when stories.add_item_to_story returns falsy (HTTP 404). The single guard covers two distinct miss conditions: the story_id does not exist, or the generation referenced in StoryItemCreate does not exist. The message combines both because the service returns one falsy signal for either.
Source
Thrown at backend/routes/stories.py:81
db: Session = Depends(get_db),
):
"""Delete a story."""
success = await stories.delete_story(story_id, db)
if not success:
raise HTTPException(status_code=404, detail="Story not found")
return {"message": "Story deleted successfully"}
@router.post("/stories/{story_id}/items", response_model=models.StoryItemDetail)
async def add_story_item(
story_id: str,
data: models.StoryItemCreate,
db: Session = Depends(get_db),
):
"""Add a generation to a story."""
item = await stories.add_item_to_story(story_id, data, db)
if not item:
raise HTTPException(status_code=404, detail="Story or generation not found")
return item
@router.delete("/stories/{story_id}/items/{item_id}")
async def remove_story_item(
story_id: str,
item_id: str,
db: Session = Depends(get_db),
):
"""Remove a story item from a story."""
success = await stories.remove_item_from_story(story_id, item_id, db)
if not success:
raise HTTPException(status_code=404, detail="Story item not found")
return {"message": "Item removed successfully"}
@router.put("/stories/{story_id}/items/times")
async def update_story_item_times(View on GitHub (pinned to 51f49dea19)
Solutions
- Verify both story_id (GET /stories/{story_id}) and the referenced generation exist before adding.
- Refresh the generations list to obtain a current generation_id.
- If the message is ambiguous in the UI, pre-check both entities to disambiguate.
- Avoid holding generation ids long-term; re-fetch before use.
Example fix
// before
await api.post(`/stories/${sid}/items`, { generation_id: gen });
// after
if (!await storyExists(sid) || !await generationExists(gen))
throw new NotFoundError('story or generation');
await api.post(`/stories/${sid}/items`, { generation_id: gen }); Defensive patterns
Strategy: validation
Validate before calling
async function canAddItem(storyId, generationId) {
const [s, g] = await Promise.all([
fetch(`/api/stories/${encodeURIComponent(storyId)}`),
fetch(`/api/generations/${encodeURIComponent(generationId)}`),
]);
return s.ok && g.ok;
} Type guard
function isItemCreate(v) { return !!v && typeof v.generation_id === 'string'; } Try / catch
try { await api.post(`/stories/${sid}/items`, payload); }
catch (e) { if (e.response?.status === 404) disambiguateStoryOrGeneration(sid, payload.generation_id); throw e; } Prevention
- Verify both story and generation exist before adding.
- Re-fetch generation ids before use; don't hold them long-term.
- Pre-check both entities to disambiguate the combined 404 message.
When it happens
Trigger: Adding a generation to a non-existent story, or referencing a generation_id that does not exist (wrong id, deleted, or belongs to another scope). The handler cannot distinguish which from the return value alone.
Common situations: Generation was deleted between creation and adding to a story. Story_id from a stale list. Generation_id copied from a different environment.
Related errors
- Story not found
- Story item not found
- Story item not found or invalid trim values
- Source version not found
- Version not found
AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12).
Data as JSON: /api/errors/8c3c6ca73898192f.
Report an issue: GitHub.