jamiepine/voicebox · error · HTTPException

Preset not found

Error message

Preset not found

What it means

HTTP 404 raised by GET /effects/presets/{preset_id} when effects_mod.get_preset() returns None, i.e. no EffectPreset row matches the preset_id (built-in or user). The handler raises 404 'Preset not found'. This is a pure lookup miss on the presets table.

Source

Thrown at backend/routes/effects.py:89

    return models.AvailableEffectsResponse(effects=[models.AvailableEffect(**e) for e in _get_effects()])


@router.get("/effects/presets", response_model=list[models.EffectPresetResponse])
async def list_effect_presets(db: Session = Depends(get_db)):
    """List all effect presets (built-in + user-created)."""
    from ..services import effects as effects_mod

    return effects_mod.list_presets(db)


@router.get("/effects/presets/{preset_id}", response_model=models.EffectPresetResponse)
async def get_effect_preset(preset_id: str, db: Session = Depends(get_db)):
    """Get a specific effect preset."""
    from ..services import effects as effects_mod

    preset = effects_mod.get_preset(preset_id, db)
    if not preset:
        raise HTTPException(status_code=404, detail="Preset not found")
    return preset


@router.post("/effects/presets", response_model=models.EffectPresetResponse)
async def create_effect_preset(
    data: models.EffectPresetCreate,
    db: Session = Depends(get_db),
):
    """Create a new effect preset."""
    from ..services import effects as effects_mod

    try:
        return effects_mod.create_preset(data, db)
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))


@router.put("/effects/presets/{preset_id}", response_model=models.EffectPresetResponse)

View on GitHub (pinned to 51f49dea19)

Solutions

  1. GET /effects/presets to list valid preset IDs before referencing one.
  2. On 404, refresh the presets list and fall back to a default/built-in preset.
  3. Do not cache preset_ids long-term; they can be deleted by the user.

Example fix

// before
const p = await fetch(`/effects/presets/${id}`).then(r => r.json());
// after
const r = await fetch(`/effects/presets/${id}`);
if (r.status === 404) { const all = await fetch('/effects/presets').then(r => r.json()); return all[0]; }
return r.json();
Defensive patterns

Strategy: validation

Validate before calling

const presets = await fetch('/effects/presets').then(r => r.json());
if (!presets.some(p => p.id === presetId)) throw new Error('preset missing');

Type guard

function isPresetList(v): v is Array<{ id: string }> { return Array.isArray(v) && v.every(p => typeof p?.id === 'string'); }

Try / catch

const r = await fetch(`/effects/presets/${id}`);
if (r.status === 404) { const all = await fetch('/effects/presets').then(r => r.json()); return all[0]; }

Prevention

When it happens

Trigger: GET /effects/presets/{preset_id} with an ID that was never created, was deleted, or is malformed.

Common situations: Referencing a user preset that was deleted; storing a preset_id across sessions without refreshing; typo or copy-paste error in the ID.

Related errors


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