jamiepine/voicebox · error · HTTPException
{error}
Error message
{error} What it means
Returned by PUT /profiles/{profile_id}/effects when validate_effects_chain() rejects the supplied chain (HTTP 400). The handler serializes each effect via model_dump, then delegates to validate_effects_chain; only if that returns a non-empty error string does it raise, using the validator's message verbatim. It means the request body parsed as ProfileEffectsUpdate but the chain contents are semantically invalid.
Source
Thrown at backend/routes/profiles.py:354
@router.put("/profiles/{profile_id}/effects", response_model=models.VoiceProfileResponse)
async def update_profile_effects(
profile_id: str,
data: models.ProfileEffectsUpdate,
db: Session = Depends(get_db),
):
"""Set or clear the default effects chain for a voice profile."""
profile = db.query(DBVoiceProfile).filter_by(id=profile_id).first()
if not profile:
raise HTTPException(status_code=404, detail="Profile not found")
if data.effects_chain is not None:
from ..utils.effects import validate_effects_chain
chain_dicts = [e.model_dump() for e in data.effects_chain]
error = validate_effects_chain(chain_dicts)
if error:
raise HTTPException(status_code=400, detail=error)
profile.effects_chain = _json.dumps(chain_dicts)
else:
profile.effects_chain = None
profile.updated_at = datetime.utcnow()
db.commit()
db.refresh(profile)
return _profile_to_response(profile)
# ── Personality endpoint ──────────────────────────────────────────────
# Only ``/profiles/{id}/compose`` remains — the UI's compose button
# produces a fresh in-character utterance the user can edit before
# speaking. Rewrite now happens inside ``/generate`` (and ``/speak``)
# when ``personality=true``; there is no standalone rewrite/respond/speak
# endpoint.
View on GitHub (pinned to 51f49dea19)
Solutions
- Inspect the exact detail string from the 400 response — it comes straight from validate_effects_chain and names the offending field/effect.
- Cross-check the effect names and parameter keys against the current backend's supported effects list.
- Validate the chain client-side against the same schema before submitting.
- Ensure each effect object includes all required keys and that numeric params are within documented ranges.
Example fix
// before
await api.put(`/profiles/${id}/effects`, { effects_chain: rawChain });
// after
const errs = validateChainClient(rawChain); // mirror of validate_effects_chain
if (errs.length) throw new UserError(errs);
await api.put(`/profiles/${id}/effects`, { effects_chain: rawChain }); Defensive patterns
Strategy: validation
Validate before calling
function validateChainClient(chain) {
const supported = new Set(['eq','compressor','reverb','gain']);
const errs = [];
for (const e of chain) {
if (!supported.has(e.type)) errs.push(`unknown effect: ${e.type}`);
if (typeof e.params?.gain === 'number' && (e.params.gain < 0 || e.params.gain > 4))
errs.push(`gain out of range on ${e.type}`);
}
return errs;
} Type guard
function isEffectsChain(v) { return Array.isArray(v) && v.every(e => e && typeof e === 'object' && typeof e.type === 'string'); } Try / catch
try { await api.put(`/profiles/${id}/effects`, { effects_chain: chain }); }
catch (e) { if (e.response?.status === 400) showUser(e.response.data.detail); throw e; } Prevention
- Mirror validate_effects_chain on the client and run it before submit.
- Build the chain from the backend's current supported-effects list, not a hardcoded copy.
- Surface the detail string verbatim to the user — it names the offending field.
When it happens
Trigger: Submitting an effects_chain with an unknown effect type, missing required parameters for an effect, out-of-range values, or a malformed effect object. Passing an empty object instead of a fully-formed effect descriptor.
Common situations: Frontend builds the chain from a stale list of supported effects after an engine upgrade that renamed/removed an effect. Copy-pasting a chain from docs for a different backend version. Negative or NaN gain values, unsupported sample-rate-dependent parameters.
Related errors
- No voice profile resolved. Pass `profile` (name or id), or c
- Generation is not completed
- {validation error from validate_effects_chain}
- {exception message from create_preset (ValueError)}
- {exception message from update_preset (ValueError)}
AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12).
Data as JSON: /api/errors/ce2a3540b4145032.
Report an issue: GitHub.