jamiepine/voicebox · error · HTTPException

Channel not found

Error message

Channel not found

What it means

HTTP 404 raised by GET /channels/{channel_id} when no AudioChannel row matches the supplied ID. The route delegates to channels.get_channel(), which queries the database by primary key and returns None on a miss; the handler then converts that None into a 404 'Channel not found'. It is a pure lookup miss, not a permission or format error.

Source

Thrown at backend/routes/channels.py:39

    data: models.AudioChannelCreate,
    db: Session = Depends(get_db),
):
    """Create a new audio channel."""
    try:
        return await channels.create_channel(data, db)
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))


@router.get("/channels/{channel_id}", response_model=models.AudioChannelResponse)
async def get_channel(
    channel_id: str,
    db: Session = Depends(get_db),
):
    """Get an audio channel by ID."""
    channel = await channels.get_channel(channel_id, db)
    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))

View on GitHub (pinned to 51f49dea19)

Solutions

  1. Call GET /channels to list all valid channel IDs and copy the exact UUID.
  2. Confirm the ID you hold came from a create/list response and was refreshed after any delete.
  3. Strip whitespace and validate the ID is a 36-char UUID before sending.
  4. Treat a 404 on this endpoint as 'resource gone' and clear it from the client cache.

Example fix

// before
const r = await fetch(`/channels/${someDeviceId}`);
// after
const list = await fetch('/channels').then(r => r.json());
const ch = list.find(c => c.id === expectedId);
if (!ch) throw new Error('channel does not exist');
const r = await fetch(`/channels/${ch.id}`);
Defensive patterns

Strategy: validation

Validate before calling

const channels = await fetch('/channels').then(r => r.json());
const exists = channels.some(c => c.id === channelId);
if (!exists) throw new Error(`channel ${channelId} not found`);

Type guard

function isChannelList(v): v is Array<{ id: string; name: string }> {
  return Array.isArray(v) && v.every(c => typeof c?.id === 'string');
}

Try / catch

const r = await fetch(`/channels/${channelId}`);
if (r.status === 404) { /* clear stale id, refresh list */ }

Prevention

When it happens

Trigger: Calling GET /channels/{channel_id} with a UUID that was never created, has been deleted, is malformed, or belongs to a different resource type (e.g. a device_id or profile_id).

Common situations: Frontend holds a stale channel_id in memory after the channel was deleted in another tab; copy-paste truncation of the UUID; trailing whitespace or surrounding quotes accidentally sent; test calling a randomly generated UUID without first creating the channel.

Related errors


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