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

  1. If the message mentions 'default channel', pick a non-default channel or create a new one.
  2. If the message is a duplicate-name error, choose a unique name or first rename the conflicting channel.
  3. Disable edit controls in the UI for channels where is_default is true.
  4. 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

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


AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12). Data as JSON: /api/errors/83314d219379bc3b. Report an issue: GitHub.