Skip to main content
Every non-2xx response, or a {success: false} JSON envelope on a 2xx, raises a typed exception instead of returning normally. All error classes are exported from the package root:

The error classes

Every exception is a normal Python exception: str(err) (or err.args[0]) is the human-readable message from the envelope, safe to log or (after your own review) surface to a user. There’s also a __repr__ that includes message, status_code, and code. code mirrors the backend’s own machine-readable error code (e.g. VALIDATION_ERROR, UNAUTHORIZED, PROJECT_NOT_ACTIVE, NOT_FOUND, EXTERNAL_USER_REQUIRED) — check the API Reference for each endpoint’s documented error responses.

What causes each error

Handling errors

Because the classes form a hierarchy, except PersonaApiError alone catches all three — order matters if you also list the subclasses first.

Common failure scenarios

Validation failure

Authentication / authorization failure

Existence-hiding 404s

get()/update()/delete() never distinguish “not found” from “not authorized” — a caller that can’t own a resource gets the same 404 NOT_FOUND as a caller asking for a nonexistent id. This is intentional (don’t build error-driven existence probes). Note that bulk_delete() is the exception: it doesn’t raise on per-id failures — see Behavior & edge cases.

Rate limiting

Only 429 is retried automatically (up to max_retries, honoring Retry-After). If all retries are exhausted, the final 429 response raises PersonaApiError with status_code == 429. See Retries and rate limits.

Non-JSON error bodies

If a failure response has no JSON body, the SDK can’t decode an envelope and raises a generic PersonaApiError with code == "NON_JSON_ERROR_RESPONSE" and the raw status code. This usually indicates a proxy/load-balancer error page rather than an API error — check your network path.

Errors on streaming calls

chat.stream() and chat.send_message() raise the same typed errors if the server responds with a normal JSON error envelope instead of starting the event stream (e.g. a 400 EXTERNAL_USER_REQUIRED when no external_user_id was set, or a 404 for a mismatched thread_id). They surface as exceptions on the generator/send_message() call — not as events inside the stream. Malformed or partial SSE frames are skipped silently (tolerant parsing), never raised.