jamiepine/voicebox · error · HTTPException
{str(e)}
Error message
{str(e)} What it means
Returned by POST /stories when stories.create_story raises any Exception (HTTP 400). The handler catches a broad Exception and forwards str(e) as detail, so the message is whatever the service threw. Because the catch is non-specific, the detail could range from validation to DB constraint errors.
Source
Thrown at backend/routes/stories.py:32
router = APIRouter()
@router.get("/stories", response_model=list[models.StoryResponse])
async def list_stories(db: Session = Depends(get_db)):
"""List all stories."""
return await stories.list_stories(db)
@router.post("/stories", response_model=models.StoryResponse)
async def create_story(
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,View on GitHub (pinned to 51f49dea19)
Solutions
- Read detail — it is str(e) from the service and usually names the failing constraint.
- Validate the StoryCreate payload (title, required fields, metadata serializability) before posting.
- If detail looks like an internal traceback rather than a user error, suspect a server bug and check backend logs.
- Avoid collisions with existing story slugs/titles if uniqueness is enforced.
Example fix
// before
await api.post('/stories', story);
// after
ensureStoryCreate(story); // checks title non-empty, metadata JSON-serializable
await api.post('/stories', story); Defensive patterns
Strategy: validation
Validate before calling
function validateStoryCreate(s) {
if (!s || typeof s.title !== 'string' || !s.title.trim()) throw new Error('title required');
if (s.metadata != null) JSON.stringify(s.metadata);
} Type guard
function isStoryCreate(v) { return !!v && typeof v.title === 'string' && v.title.trim().length > 0; } Try / catch
try { await api.post('/stories', story); }
catch (e) { if (e.response?.status === 400) showUser(e.response.data.detail); throw e; } Prevention
- Validate title and required fields before posting.
- Ensure metadata is JSON-serializable and within size limits.
- Avoid duplicate slugs/titles if uniqueness is enforced.
- If detail looks like a traceback, suspect a server bug, not user error.
When it happens
Trigger: Submitting a StoryCreate body whose fields violate a constraint inside create_story (e.g., invalid title length, duplicate slug, malformed metadata). Also any unexpected service-layer exception surfaces here as 400.
Common situations: Missing required StoryCreate fields that pass Pydantic but fail DB constraints. Duplicate unique key (slug/title). Unserializable metadata payload. The broad catch can mask server-side bugs as 400.
Related errors
- Invalid timecode update request
- Invalid reorder request - ensure all generation IDs belong t
- Story item not found or invalid trim values
- {error}
- No voice profile resolved. Pass `profile` (name or id), or c
AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12).
Data as JSON: /api/errors/7fc39b4424b96fe1.
Report an issue: GitHub.