jamiepine/voicebox · warning · ValueError
Cannot modify the default channel
Error message
Cannot modify the default channel
What it means
Raised as ValueError (HTTP 400) by update_channel when the loaded channel has is_default=True. The default channel is immutable by design — its name and device mappings cannot be changed through update_channel. The guard fires after the channel is fetched but before any field mutation, so no partial write occurs.
Source
Thrown at backend/services/channels.py:121
name=channel.name,
is_default=channel.is_default,
device_ids=data.device_ids,
created_at=channel.created_at,
)
async def update_channel(
channel_id: str,
data: AudioChannelUpdate,
db: Session,
) -> Optional[AudioChannelResponse]:
"""Update an audio channel."""
channel = db.query(DBAudioChannel).filter_by(id=channel_id).first()
if not channel:
return None
if channel.is_default:
raise ValueError("Cannot modify the default channel")
# Update name if provided
if data.name is not None:
# Check if name already exists (excluding current channel)
existing = db.query(DBAudioChannel).filter(
DBAudioChannel.name == data.name,
DBAudioChannel.id != channel_id
).first()
if existing:
raise ValueError(f"Channel with name '{data.name}' already exists")
channel.name = data.name
# Update device mappings if provided
if data.device_ids is not None:
# Delete existing mappings
db.query(DBChannelDeviceMapping).filter_by(channel_id=channel_id).delete()
# Add new mappingsView on GitHub (pinned to 51f49dea19)
Solutions
- In the UI, disable editing for the channel with is_default=true (it's returned in AudioChannelResponse).
- Route all desired device assignments through a non-default channel; create one if needed.
- If you genuinely need to alter the default channel's devices, do so via direct DB seeding/migration, not this endpoint.
Example fix
// before
if (selected) await api.updateChannel(selected.id, patch);
// after
if (selected && !selected.is_default) {
await api.updateChannel(selected.id, patch);
} else {
notify('The default channel cannot be modified');
} Defensive patterns
Strategy: validation
Validate before calling
function isEditableChannel(ch) {
return Boolean(ch) && ch.is_default === false;
}
if (!isEditableChannel(channel)) { notify('The default channel cannot be modified'); return; } Type guard
function isMutableChannel(ch) {
return Boolean(ch) && ch.is_default === false;
} Try / catch
try { await api.updateChannel(id, patch); }
catch (e) {
if (e.status === 400 && /default channel/.test(e.detail)) notify('Default channel is read-only');
else throw e;
} Prevention
- Disable the edit form when is_default is true.
- Don't include the default channel id in bulk device-mapping updates.
- Alter the default channel only via seeding/migration, never this endpoint.
When it happens
Trigger: PUT /channels/{channel_id} targeting the channel whose is_default flag is True — typically the seeded 'Default' channel. Includes attempts that only change device_ids (the guard is unconditional on is_default, not gated on whether name is being changed).
Common situations: User selects the Default channel in an edit UI and saves; client auto-saves device-mapping changes without checking is_default; trying to rename the default channel.
Related errors
- Cannot delete the default channel
- Channel with name '{data.name}' already exists
- Profile {profile_id} not found
- {exception message from create_channel (ValueError)}
- {exception message from update_channel (ValueError)}
AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12).
Data as JSON: /api/errors/77e53e2ee9ea9223.
Report an issue: GitHub.