{"record":{"id":"347636a0cc9320eb","repo":"jamiepine/voicebox","slug":"cannot-delete-built-in-presets","errorCode":null,"errorMessage":"Cannot delete built-in presets","messagePattern":"Cannot delete built-in presets","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"warning","filePath":"backend/services/effects.py","lineNumber":116,"sourceCode":"\n        chain_dicts = [e.model_dump() for e in data.effects_chain]\n        error = validate_effects_chain(chain_dicts)\n        if error:\n            raise ValueError(error)\n        preset.effects_chain = json.dumps(chain_dicts)\n\n    db.commit()\n    db.refresh(preset)\n    return _preset_response(preset)\n\n\ndef delete_preset(preset_id: str, db: Session) -> bool:\n    \"\"\"Delete a user effect preset. Cannot delete built-in presets.\"\"\"\n    preset = db.query(DBEffectPreset).filter_by(id=preset_id).first()\n    if not preset:\n        return False\n    if preset.is_builtin:\n        raise ValueError(\"Cannot delete built-in presets\")\n\n    db.delete(preset)\n    db.commit()\n    return True\n","sourceCodeStart":98,"sourceCodeEnd":121,"githubUrl":"https://github.com/jamiepine/voicebox/blob/51f49dea198384b4eb6087b72c17057c6eb1c1cd/backend/services/effects.py#L98-L121","documentation":"delete_preset() refuses to remove any row with is_builtin True. Built-in presets are managed by application seed data and are not user-deletable. The check runs before db.delete().","triggerScenarios":"DELETE /presets/{id} where {id} resolves to a built-in preset (is_builtin=True).","commonSituations":"Bulk-delete UI; user trying to 'clean up' the default preset list; DELETE on a preset whose id was assumed to be user-owned.","solutions":["Hide the delete control for presets where is_builtin is true.","Filter the deletable list to is_builtin == False.","If a built-in must be hidden, add a visibility flag instead of deleting it."],"exampleFix":"# before\ndelete_preset(builtin_id, db)  # raises\n\n# after — only delete user presets\np = get_preset(pid, db)\nif p and not p.is_builtin:\n    delete_preset(pid, db)","handlingStrategy":"validation","validationCode":"from backend.services.effects import get_preset\n\ndef is_deletable(preset_id, db) -> bool:\n    p = get_preset(preset_id, db)\n    return p is not None and not p.is_builtin","typeGuard":"def is_builtin_preset(p) -> bool:\n    return bool(getattr(p, \"is_builtin\", False))","tryCatchPattern":"try:\n    delete_preset(preset_id, db)\nexcept ValueError as e:\n    if \"built-in\" in str(e):\n        # return 403, suppress the delete control in UI\n        ...\n    raise","preventionTips":["Filter the delete action by is_builtin on the client.","Don't expose delete affordances on read-only presets."],"tags":["effects","presets","readonly","built-in","delete"],"backgroundTag":null,"analyzedSha":"51f49dea198384b4eb6087b72c17057c6eb1c1cd","analyzedAt":"2026-08-12T16:51:42.824Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}