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

  1. Disable edit controls in the UI for presets where is_builtin is true.
  2. If a variant is wanted, clone the built-in into a new user preset (create_preset) and edit that copy.
  3. 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

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


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