{"record":{"id":"f9884e308dc7e281","repo":"jamiepine/voicebox","slug":"channel-not-found","errorCode":null,"errorMessage":"Channel not found","messagePattern":"Channel not found","errorType":"http","errorClass":"HTTPException","httpStatus":404,"severity":"error","filePath":"backend/routes/channels.py","lineNumber":39,"sourceCode":"    data: models.AudioChannelCreate,\n    db: Session = Depends(get_db),\n):\n    \"\"\"Create a new audio channel.\"\"\"\n    try:\n        return await channels.create_channel(data, db)\n    except ValueError as e:\n        raise HTTPException(status_code=400, detail=str(e))\n\n\n@router.get(\"/channels/{channel_id}\", response_model=models.AudioChannelResponse)\nasync def get_channel(\n    channel_id: str,\n    db: Session = Depends(get_db),\n):\n    \"\"\"Get an audio channel by ID.\"\"\"\n    channel = await channels.get_channel(channel_id, db)\n    if not channel:\n        raise HTTPException(status_code=404, detail=\"Channel not found\")\n    return channel\n\n\n@router.put(\"/channels/{channel_id}\", response_model=models.AudioChannelResponse)\nasync def update_channel(\n    channel_id: str,\n    data: models.AudioChannelUpdate,\n    db: Session = Depends(get_db),\n):\n    \"\"\"Update an audio channel.\"\"\"\n    try:\n        channel = await channels.update_channel(channel_id, data, db)\n        if not channel:\n            raise HTTPException(status_code=404, detail=\"Channel not found\")\n        return channel\n    except ValueError as e:\n        raise HTTPException(status_code=400, detail=str(e))\n","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/jamiepine/voicebox/blob/51f49dea198384b4eb6087b72c17057c6eb1c1cd/backend/routes/channels.py#L21-L57","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Call GET /channels to list all valid channel IDs and copy the exact UUID.","Confirm the ID you hold came from a create/list response and was refreshed after any delete.","Strip whitespace and validate the ID is a 36-char UUID before sending.","Treat a 404 on this endpoint as 'resource gone' and clear it from the client cache."],"exampleFix":"// before\nconst r = await fetch(`/channels/${someDeviceId}`);\n// after\nconst list = await fetch('/channels').then(r => r.json());\nconst ch = list.find(c => c.id === expectedId);\nif (!ch) throw new Error('channel does not exist');\nconst r = await fetch(`/channels/${ch.id}`);","handlingStrategy":"validation","validationCode":"const channels = await fetch('/channels').then(r => r.json());\nconst exists = channels.some(c => c.id === channelId);\nif (!exists) throw new Error(`channel ${channelId} not found`);","typeGuard":"function isChannelList(v): v is Array<{ id: string; name: string }> {\n  return Array.isArray(v) && v.every(c => typeof c?.id === 'string');\n}","tryCatchPattern":"const r = await fetch(`/channels/${channelId}`);\nif (r.status === 404) { /* clear stale id, refresh list */ }","preventionTips":["Always source channel IDs from a fresh GET /channels response.","Clear cached IDs after observing a delete.","Strip whitespace and validate UUID format before sending."],"tags":["channels","http","not-found","fastapi"],"backgroundTag":null,"analyzedSha":"51f49dea198384b4eb6087b72c17057c6eb1c1cd","analyzedAt":"2026-08-12T16:51:42.824Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}