jamiepine/voicebox · error · ValueError
Effect '{effect_type}' at index {i}: param '{param_name}' mu
Error message
Effect '{effect_type}' at index {i}: param '{param_name}' must be between {pdef['min']} and {pdef['max']} (got {value}) What it means
validate_effects_chain() (backend/utils/effects.py) checks each numeric param against the min/max recorded in EFFECT_REGISTRY[type]['params'][name]. A value below min or above max returns this message, which create_preset()/update_preset() raise as ValueError. This keeps pedalboard construction inside valid DSP ranges before it reaches the DB or build_pedalboard().
Source
Thrown at backend/services/effects.py:102
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)
def delete_preset(preset_id: str, db: Session) -> bool:
"""Delete a user effect preset. Cannot delete built-in presets."""
preset = db.query(DBEffectPreset).filter_by(id=preset_id).first()
if not preset:
return False
if preset.is_builtin:
raise ValueError("Cannot delete built-in presets")
db.delete(preset)
db.commit()
return TrueView on GitHub (pinned to 51f49dea19)
Solutions
- Clamp the value to [min, max] for that param (see EFFECT_REGISTRY[type]['params'][name]).
- Fetch param schemas via get_available_effects() and enforce the same min/max/step on the client.
- Round to the registered 'step' increment as well.
Example fix
// before — pitch_shift min is -12
{"type": "pitch_shift", "params": {"semitones": -20}}
// after
{"type": "pitch_shift", "params": {"semitones": -12}} Defensive patterns
Strategy: validation
Validate before calling
from backend.utils.effects import EFFECT_REGISTRY
def clamp_param(effect_type, name, value):
p = EFFECT_REGISTRY[effect_type]["params"][name]
return max(p["min"], min(p["max"], value)) Type guard
from backend.utils.effects import EFFECT_REGISTRY
def in_range(effect_type, name, value) -> bool:
p = EFFECT_REGISTRY[effect_type]["params"][name]
return isinstance(value, (int, float)) and p["min"] <= value <= p["max"] Try / catch
try:
create_preset(data, db)
except ValueError as e:
if "must be between" in str(e):
# parse range, re-clamp, resubmit
...
raise Prevention
- Bind UI inputs to the same min/max/step from EFFECT_REGISTRY.
- Validate the whole chain client-side before submit.
When it happens
Trigger: Saving a preset with e.g. gain_db=60 (max 40), pitch_shift semitones=-20 (min -12), chorus rate_hz=0 (min 0.01), or lowpass cutoff above 20000.
Common situations: Frontend slider bounds out of sync with the backend registry; manual JSON edit pushing an extreme value; stale cached effect schema on the client.
Related errors
- Unknown effect type '{effect_type}' at index {i}. Available:
- A preset named '{data.name}' already exists
- Generation is not completed
- {validation error from validate_effects_chain}
- {exception message from create_preset (ValueError)}
AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12).
Data as JSON: /api/errors/a0c0c6d8813edd63.
Report an issue: GitHub.