jamiepine/voicebox · error · HTTPException
Story not found
Error message
Story not found
What it means
Returned by GET /stories/{story_id} when stories.get_story returns a falsy value (HTTP 404). The lookup runs first; the detail response is only built if a story is found. It is a straightforward entity-miss on the path parameter.
Source
Thrown at backend/routes/stories.py:43
data: models.StoryCreate,
db: Session = Depends(get_db),
):
"""Create a new story."""
try:
return await stories.create_story(data, db)
except Exception as e:
raise HTTPException(status_code=400, detail=str(e))
@router.get("/stories/{story_id}", response_model=models.StoryDetailResponse)
async def get_story(
story_id: str,
db: Session = Depends(get_db),
):
"""Get a story with all its items."""
story = await stories.get_story(story_id, db)
if not story:
raise HTTPException(status_code=404, detail="Story not found")
return story
@router.put("/stories/{story_id}", response_model=models.StoryResponse)
async def update_story(
story_id: str,
data: models.StoryCreate,
db: Session = Depends(get_db),
):
"""Update a story."""
story = await stories.update_story(story_id, data, db)
if not story:
raise HTTPException(status_code=404, detail="Story not found")
return story
@router.delete("/stories/{story_id}")
async def delete_story(View on GitHub (pinned to 51f49dea19)
Solutions
- Verify story_id against the GET /stories list before deep-linking.
- On 404, return the user to the stories list rather than auto-retrying.
- Sanitize story_id (trim, validate UUID format) before the request.
- Reconcile client-side caches with the server list.
Example fix
// before
window.location = `/stories/${id}`;
// after
if (!await storyExists(id)) redirect('/stories');
window.location = `/stories/${id}`; Defensive patterns
Strategy: validation
Validate before calling
async function storyExists(id) {
const r = await fetch(`/api/stories/${encodeURIComponent(id)}`);
return r.ok;
} Type guard
function isStoryId(v) { return typeof v === 'string' && v.trim().length >= 8; } Try / catch
try { await api.get(`/stories/${id}`); }
catch (e) { if (e.response?.status === 404) redirectToStoriesList(); throw e; } Prevention
- Validate story id format and existence before deep-linking.
- Reconcile bookmarked URLs against the current list.
- Return to the list rather than retrying on 404.
When it happens
Trigger: GET /stories/{story_id} where story_id is unknown, deleted, or belongs to another scope. Reading a story that was removed between list and detail fetch.
Common situations: Stale bookmarked URL. Story deleted in another session. Typo or truncated UUID in the path.
Related errors
- Story or generation not found
- Story item not found
- Story item not found or invalid trim values
- No ROCm backend found to delete
- Voice profile '{data.profile}' not found.
AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12).
Data as JSON: /api/errors/fe8776dd098f03ce.
Report an issue: GitHub.