jamiepine/voicebox · error · HTTPException
{exception message from delete_preset (ValueError)}
Error message
{exception message from delete_preset (ValueError)} What it means
Returned as HTTP 400 by DELETE /effects/presets/{preset_id}. effects.delete_preset() raises ValueError("Cannot delete built-in presets") when the looked-up row has is_builtin=True. The route catches ValueError and surfaces str(e) as the detail. Built-in presets are seed data shipped with the app and are intentionally immutable.
Source
Thrown at backend/routes/effects.py:135
result = effects_mod.update_preset(preset_id, data, db)
if not result:
raise HTTPException(status_code=404, detail="Preset not found")
return result
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
@router.delete("/effects/presets/{preset_id}")
async def delete_effect_preset(preset_id: str, db: Session = Depends(get_db)):
"""Delete a user effect preset."""
from ..services import effects as effects_mod
try:
if not effects_mod.delete_preset(preset_id, db):
raise HTTPException(status_code=404, detail="Preset not found")
return {"status": "deleted"}
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
@router.get(
"/generations/{generation_id}/versions",
response_model=list[models.GenerationVersionResponse],
)
async def list_generation_versions(
generation_id: str,
db: Session = Depends(get_db),
):
"""List all versions for a generation."""
gen = await history.get_generation(generation_id, db)
if not gen:
raise HTTPException(status_code=404, detail="Generation not found")
from ..services import versions as versions_mod
return versions_mod.list_versions(generation_id, db)View on GitHub (pinned to 51f49dea19)
Solutions
- Filter the preset list by is_builtin === false before offering delete in the UI.
- If bulk cleanup is needed, only delete user presets and treat built-ins as read-only reference data.
- Add a client-side guard: if (preset.is_builtin) return; before calling delete.
- Re-seed built-ins via the app's seeding path rather than deleting and recreating them.
Example fix
// before
for (const p of allPresets) await api.delete(`/effects/presets/${p.id}`);
// after
for (const p of allPresets) {
if (p.is_builtin) continue; // built-ins are immutable
await api.delete(`/effects/presets/${p.id}`);
} Defensive patterns
Strategy: validation
Validate before calling
# Never attempt to delete built-in presets.
preset = next((p for p in effects_mod.list_presets(db) if p.id == preset_id), None)
if preset is None:
return # will 404 instead
if preset.is_builtin:
return # would 400 — skip; built-ins are immutable
# safe to delete Type guard
def is_user_preset(preset) -> bool:
"""True only for a deletable, user-created preset."""
return preset is not None and not bool(preset.is_builtin) Try / catch
try:
client.delete(f'/effects/presets/{preset_id}')
except HTTPStatusError as e:
if e.response.status_code == 400 and 'built-in' in e.response.json()['detail']:
# expected when hitting a built-in — filter these out upstream
return
raise Prevention
- Filter the preset list by is_builtin === false before any bulk delete.
- Treat built-in presets as read-only reference data in the UI.
- Add a client-side guard that disables delete for built-ins.
- Re-seed built-ins through the app's seeding path, never via delete+recreate.
When it happens
Trigger: DELETE /effects/presets/{preset_id} where preset_id resolves to a row with is_builtin=True; iterating over GET /effects/presets and calling delete on every entry including built-ins; UI failing to hide/disable the delete button for built-in presets.
Common situations: A 'reset to defaults' feature that tries to wipe all presets; bulk-delete scripts that do not filter on is_builtin; frontend that does not read the is_builtin flag on EffectPresetResponse; running a destructive migration without guarding built-ins.
Related errors
- {e}
- Source version not found
- Cannot delete the last remaining version
- Only failed generations can be retried
- Generation must be completed to regenerate
AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12).
Data as JSON: /api/errors/528e4dddc856bf10.
Report an issue: GitHub.