jamiepine/voicebox · error · HTTPException

{exception message from delete_channel (ValueError)}

Error message

{exception message from delete_channel (ValueError)}

What it means

HTTP 400 raised by DELETE /channels/{channel_id} when channels.delete_channel() raises ValueError. The service raises exactly one ValueError here: 'Cannot delete the default channel', fired when the targeted row has is_default=true. The handler re-wraps the message into a 400. The default channel is protected and cannot be removed through this endpoint.

Source

Thrown at backend/routes/channels.py:71

            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")
async def get_channel_voices(
    channel_id: str,
    db: Session = Depends(get_db),
):
    """Get list of profile IDs assigned to a channel."""
    try:
        profile_ids = await channels.get_channel_voices(channel_id, db)
        return {"profile_ids": profile_ids}
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))


@router.put("/channels/{channel_id}/voices")
async def set_channel_voices(
    channel_id: str,

View on GitHub (pinned to 51f49dea19)

Solutions

  1. Do not expose a delete action for channels where is_default is true.
  2. If you need fewer channels, delete user-created ones or repoint devices off the default first.
  3. Surface the detail verbatim so the user understands it is a protected resource.

Example fix

// before
await fetch(`/channels/${id}`, { method: 'DELETE' });
// after
if (channel.is_default) { alert('The default channel cannot be deleted'); return; }
await fetch(`/channels/${id}`, { method: 'DELETE' });
Defensive patterns

Strategy: validation

Validate before calling

if (channel.is_default) throw new Error('default channel is protected from deletion');

Type guard

function isProtectedChannel(c): c is { is_default: true } { return c?.is_default === true; }

Try / catch

const r = await fetch(`/channels/${id}`, { method: 'DELETE' });
if (r.status === 400) { const { detail } = await r.json(); /* 'Cannot delete the default channel' */ }

Prevention

When it happens

Trigger: Issuing DELETE against the channel whose is_default flag is true (the seeded/primary channel).

Common situations: User selects the system default channel in a delete UI; automation enumerates all channels and tries to delete each; confusing the default channel with a user-created one.

Related errors


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