jamiepine/voicebox · warning · ValueError
Cannot modify built-in presets
Error message
Cannot modify built-in presets
What it means
update_preset() refuses to mutate any row where is_builtin is True. Built-in presets (seeded from BUILTIN_PRESETS in utils/effects.py: robotic, radio, echo_chamber, deep_voice) are read-only reference data. The check runs before any field assignment.
Source
Thrown at backend/services/effects.py:91
is_builtin=False,
)
db.add(preset)
try:
db.commit()
except IntegrityError:
db.rollback()
raise ValueError(f"A preset named '{data.name}' already exists")
db.refresh(preset)
return _preset_response(preset)
def update_preset(preset_id: str, data: EffectPresetUpdate, db: Session) -> Optional[EffectPresetResponse]:
"""Update a user effect preset. Cannot modify built-in presets."""
preset = db.query(DBEffectPreset).filter_by(id=preset_id).first()
if not preset:
return None
if preset.is_builtin:
raise ValueError("Cannot modify built-in presets")
if data.name is not None:
preset.name = data.name
if data.description is not None:
preset.description = data.description
if data.effects_chain is not None:
chain_dicts = [e.model_dump() for e in data.effects_chain]
error = validate_effects_chain(chain_dicts)
if error:
raise ValueError(error)
preset.effects_chain = json.dumps(chain_dicts)
db.commit()
db.refresh(preset)
return _preset_response(preset)
View on GitHub (pinned to 51f49dea19)
Solutions
- Disable edit controls in the UI for presets where is_builtin is true.
- If a variant is wanted, clone the built-in into a new user preset (create_preset) and edit that copy.
- Verify the preset_id being updated resolves to a user preset before calling update_preset().
Example fix
# before
update_preset(builtin_id, data, db) # raises
# after — clone then edit a user copy
src = get_preset(builtin_id, db)
user = create_preset(EffectPresetCreate(
name=f'{src.name} (copy)',
description=src.description,
effects_chain=src.effects_chain,
), db)
update_preset(user.id, data, db) Defensive patterns
Strategy: validation
Validate before calling
from backend.services.effects import get_preset
def is_editable(preset_id, db) -> bool:
p = get_preset(preset_id, db)
return p is not None and not p.is_builtin Type guard
def is_builtin_preset(p) -> bool:
return bool(getattr(p, "is_builtin", False)) Try / catch
try:
update_preset(preset_id, data, db)
except ValueError as e:
if "built-in" in str(e):
# hide/disable the edit affordance for this preset
...
raise Prevention
- Surface is_builtin in list responses so the UI can mark non-editable rows.
- Clone-to-edit instead of mutating built-ins.
When it happens
Trigger: PUT /presets/{id} where {id} resolves to a preset with is_builtin=True.
Common situations: UI lists built-in and user presets together without distinguishing them; user clicks Edit on a built-in row.
Related errors
- Cannot delete built-in presets
- {exception message from delete_preset (ValueError)}
- Unknown effect type '{effect_type}' at index {i}. Available:
- A preset named '{data.name}' already exists
- Effect '{effect_type}' at index {i}: param '{param_name}' mu
AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12).
Data as JSON: /api/errors/c7668120c4cbdbdd.
Report an issue: GitHub.