jamiepine/voicebox · error · HTTPException
Invalid reorder request - ensure all generation IDs belong t
Error message
Invalid reorder request - ensure all generation IDs belong to this story
What it means
Returned by PUT /stories/{story_id}/items/reorder when stories.reorder_story_items returns None (HTTP 400). The handler uses None (distinguished from an empty list) to signal that the supplied generation_ids do not all belong to the story, so the reorder is rejected entirely — partial reorders are not applied.
Source
Thrown at backend/routes/stories.py:120
db: Session = Depends(get_db),
):
"""Update story item timecodes."""
success = await stories.update_story_item_times(story_id, data, db)
if not success:
raise HTTPException(status_code=400, detail="Invalid timecode update request")
return {"message": "Item timecodes updated successfully"}
@router.put("/stories/{story_id}/items/reorder", response_model=list[models.StoryItemDetail])
async def reorder_story_items(
story_id: str,
data: models.StoryItemReorder,
db: Session = Depends(get_db),
):
"""Reorder story items and recalculate timecodes."""
items = await stories.reorder_story_items(story_id, data.generation_ids, db)
if items is None:
raise HTTPException(
status_code=400, detail="Invalid reorder request - ensure all generation IDs belong to this story"
)
return items
@router.put("/stories/{story_id}/items/{item_id}/move", response_model=models.StoryItemDetail)
async def move_story_item(
story_id: str,
item_id: str,
data: models.StoryItemMove,
db: Session = Depends(get_db),
):
"""Move a story item (update position and/or track)."""
item = await stories.move_story_item(story_id, item_id, data, db)
if item is None:
raise HTTPException(status_code=404, detail="Story item not found")
return item
View on GitHub (pinned to 51f49dea19)
Solutions
- Rebuild the full ordered generation_ids list from the current GET /stories/{story_id} detail before reordering.
- Ensure the reorder payload is a permutation of exactly the story's current item generation ids (no missing, no extra).
- After any split/trim/move, refresh the detail so ids are current.
- Validate set equality client-side: same set as the story's items.
Example fix
// before
await api.put(`/stories/${sid}/items/reorder`, { generation_ids: order });
// after
const current = (await getStory(sid)).items.map(i => i.generation_id);
if (new Set([...order, ...current]).size !== current.length) throw new Error('order set mismatch');
await api.put(`/stories/${sid}/items/reorder`, { generation_ids: order }); Defensive patterns
Strategy: validation
Validate before calling
function validateReorder(order, storyItems) {
const current = storyItems.map(i => i.generation_id).sort();
const sent = [...order].sort();
if (current.length !== sent.length) throw new Error('count mismatch');
for (let i = 0; i < current.length; i++) if (current[i] !== sent[i]) throw new Error('set mismatch');
} Type guard
function isReorder(v) { return Array.isArray(v) && v.every(x => typeof x === 'string'); } Try / catch
try { await api.put(`/stories/${sid}/items/reorder`, { generation_ids: order }); }
catch (e) { if (e.response?.status === 400) { await refreshStory(sid); rebuildOrder(); } throw e; } Prevention
- Rebuild the full ordered list from the current story detail before reordering.
- Ensure the payload is a permutation of exactly the story's current generation ids.
- Refresh detail after split/trim/move so ids are current.
When it happens
Trigger: Reorder request whose generation_ids include an id not in the story, or omit some/all current items. The service validates the set matches the story's items and returns None on mismatch.
Common situations: Client reorder list built from a stale story view. Split/trim created new item ids not reflected in the client. Drag-and-drop UI that dropped an item from the ordering.
Related errors
- {str(e)}
- Invalid timecode update request
- 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/162d137fff39181b.
Report an issue: GitHub.