jamiepine/voicebox · error · ValueError
Channel {channel_id} not found
Error message
Channel {channel_id} not found What it means
Raised as ValueError (translated to HTTP 400 by PUT /channels/{channel_id}/voices) when no DBAudioChannel matches channel_id. set_channel_voices verifies the channel exists before touching any mapping rows. Note the route maps all ValueError to 400, so a missing channel is reported as 400 rather than the more conventional 404 — clients should treat it as 'not found'.
Source
Thrown at backend/services/channels.py:205
async def get_channel_voices(channel_id: str, db: Session) -> List[str]:
"""Get list of profile IDs assigned to a channel."""
mappings = db.query(DBProfileChannelMapping).filter_by(
channel_id=channel_id
).all()
return [m.profile_id for m in mappings]
async def set_channel_voices(
channel_id: str,
data: ChannelVoiceAssignment,
db: Session,
) -> None:
"""Set which voices are assigned to a channel."""
# Verify channel exists
channel = db.query(DBAudioChannel).filter_by(id=channel_id).first()
if not channel:
raise ValueError(f"Channel {channel_id} not found")
# Verify all profiles exist
for profile_id in data.profile_ids:
profile = db.query(DBVoiceProfile).filter_by(id=profile_id).first()
if not profile:
raise ValueError(f"Profile {profile_id} not found")
# Delete existing mappings for this channel
db.query(DBProfileChannelMapping).filter_by(channel_id=channel_id).delete()
# Add new mappings
for profile_id in data.profile_ids:
mapping = DBProfileChannelMapping(
profile_id=profile_id,
channel_id=channel_id,
)
db.add(mapping)
View on GitHub (pinned to 51f49dea19)
Solutions
- GET /channels first and ensure channel_id is present before assigning voices.
- On 400 with 'Channel ... not found', invalidate the local channel and refresh.
- Upstream, consider routing missing-channel through 404 to disambiguate from a bad profile_ids value (also a 400).
Example fix
// before
await api.setChannelVoices(channelId, { profile_ids });
// after
const exists = (await api.listChannels()).some(c => c.id === channelId);
if (!exists) { refreshChannels(); return; }
await api.setChannelVoices(channelId, { profile_ids }); Defensive patterns
Strategy: validation
Validate before calling
async function assignVoicesToExistingChannel(api, channelId, profileIds) {
const channels = await api.listChannels();
if (!channels.some(c => c.id === channelId)) {
throw new Error('channel not found');
}
return api.setChannelVoices(channelId, { profile_ids: profileIds });
} Type guard
function isLiveChannelId(channels, id) {
return Array.isArray(channels) && channels.some(c => c.id === id);
} Try / catch
try { await api.setChannelVoices(channelId, { profile_ids }); }
catch (e) {
// route returns 400 for a missing channel; treat as not-found
if (e.status === 400 && /Channel .* not found/.test(e.detail)) {
await refreshChannels(); notify('Channel no longer exists');
} else throw e;
} Prevention
- GET /channels first; only allow assignment to ids in that list.
- Treat a 400 'Channel ... not found' as a removal — refresh and re-render.
- Note the route reports missing channels as 400, not 404.
When it happens
Trigger: PUT /channels/{channel_id}/voices with a channel_id that doesn't exist (deleted, typo, belongs to another scope). The profile_ids are not yet validated at this point, so this fires first.
Common situations: Stale channel_id in the client after deletion; voice-assignment UI opened on a channel that was removed elsewhere; copy/paste id error.
Related errors
- Channel not found
- {exception message from set_channel_voices (ValueError)}
- Story item not found or invalid split point
- Story item or version not found
- Channel with name '{data.name}' already exists
AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12).
Data as JSON: /api/errors/b6e18da8e676f8be.
Report an issue: GitHub.