jamiepine/voicebox · error · HTTPException
{exception message from update_channel (ValueError)}
Error message
{exception message from update_channel (ValueError)} What it means
HTTP 400 raised by PUT /channels/{channel_id} when channels.update_channel() raises ValueError. The service raises ValueError in exactly two business-rule cases: 'Cannot modify the default channel' (channel.is_default is true) and "Channel with name '{name}' already exists" (name collides with another row). The handler re-wraps the exception message verbatim into the 400 detail. It is a state/conflict error, not a not-found error.
Source
Thrown at backend/routes/channels.py:56
if not channel:
raise HTTPException(status_code=404, detail="Channel not found")
return channel
@router.put("/channels/{channel_id}", response_model=models.AudioChannelResponse)
async def update_channel(
channel_id: str,
data: models.AudioChannelUpdate,
db: Session = Depends(get_db),
):
"""Update an audio channel."""
try:
channel = await channels.update_channel(channel_id, data, db)
if not channel:
raise HTTPException(status_code=404, detail="Channel not found")
return channel
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
@router.delete("/channels/{channel_id}")
async def delete_channel(
channel_id: str,
db: Session = Depends(get_db),
):
"""Delete an audio channel."""
try:
success = await channels.delete_channel(channel_id, db)
if not success:
raise HTTPException(status_code=404, detail="Channel not found")
return {"message": "Channel deleted successfully"}
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
@router.get("/channels/{channel_id}/voices")View on GitHub (pinned to 51f49dea19)
Solutions
- If the message mentions 'default channel', pick a non-default channel or create a new one.
- If the message is a duplicate-name error, choose a unique name or first rename the conflicting channel.
- Disable edit controls in the UI for channels where is_default is true.
- Surface the exact detail string to the user; it identifies the violated rule.
Example fix
// before
await fetch(`/channels/${id}`, { method: 'PUT', body: JSON.stringify({ name: 'Main' }) });
// after
if (channel.is_default) { alert('Default channel cannot be edited'); return; }
const names = await fetch('/channels').then(r => r.json()).then(cs => cs.map(c => c.name));
if (names.includes(newName)) { alert('Name already in use'); return; }
await fetch(`/channels/${id}`, { method: 'PUT', body: JSON.stringify({ name: newName }) }); Defensive patterns
Strategy: validation
Validate before calling
if (channel.is_default) throw new Error('cannot modify default channel');
const names = (await fetch('/channels').then(r => r.json())).map(c => c.name);
if (names.includes(data.name)) throw new Error('name already used'); Type guard
function isDefaultChannel(c): c is { is_default: true } { return c?.is_default === true; } Try / catch
try {
const r = await fetch(`/channels/${id}`, { method:'PUT', body: JSON.stringify(data) });
if (r.status === 400) { const { detail } = await r.json(); showUser(detail); }
} catch (e) { /* network */ } Prevention
- Never edit the default channel; create a new one instead.
- Check name uniqueness against the live list before submitting.
- Surface the server's detail string so the user knows which rule fired.
When it happens
Trigger: PUTting to a channel that is the default (is_default=true), or supplying a name that another non-default channel already uses.
Common situations: Attempting to rename a channel to a duplicate name; trying to edit the seeded default channel instead of a user-created one; UI not disabling the edit form for the default channel.
Related errors
- {exception message from delete_channel (ValueError)}
- {exception message from set_channel_voices (ValueError)}
- {exception message from create_preset (ValueError)}
- {exception message from update_preset (ValueError)}
- Channel not found
AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12).
Data as JSON: /api/errors/83314d219379bc3b.
Report an issue: GitHub.