Skip to main content
Every authorization failure carries a semantic code and an actionable message. The SDK surfaces them as typed errors so your app can show the right next step (“re-subscribe”, “update card”, “use a dev key”) instead of a flat 401.

The taxonomy

Five classes, mapped to failure domains:
Branch on error.code, not the subclass. Codes are stable; the class is just the domain bucket.

Authorization codes

The edge worker verifies the key and maps the rejection to one envelope. session_expired realistically happens when a tab is backgrounded long enough that throttled refresh ticks let the session lapse. It is never recoverable by retry — only a fresh init (a reload) recovers, so prompt the user immediately.

Client-side codes (no network)

Some LipsyncErrors are thrown entirely client-side and still carry .code:
See Offline lip sync and the timeline model.

Wire format

Every error response is JSON with Content-Type: application/json; the HTTP status is the envelope status:
The SDK parses this into the typed error’s .code / .message. When a body is not JSON (5xx, network blip) the SDK synthesizes a status-derived envelope, so .code is always present.

Next

Licensing & keys

Why these refusals happen.

API conventions

Why the taxonomy is shaped this way.

Troubleshooting

Fixing them in practice.