Errors

Every failure raises a typed exception chosen by HTTP status, carrying the API's error code and request id.

Every API error raises an exception. The class is chosen by HTTP status; the machine-readable code rides along for finer dispatch.

from ellipsis import NotFoundError, RateLimitError

try:
    session = client.sessions.get("session_missing").session
except NotFoundError as error:
    print(error.code, error.request_id)
except RateLimitError:
    ...

The hierarchy

EllipsisError
├── TransportError        the request never got a response (DNS, TLS, timeout)
└── APIError              a non-2xx response
    ├── AuthenticationError   401  token missing, invalid, or revoked
    ├── ForbiddenError        403  authenticated, not allowed
    ├── NotFoundError         404  no such resource in this account
    ├── ConflictError         409  conflicts with current state
    ├── UnprocessableError    422  request shape failed validation
    ├── RateLimitError        429  slow down
    └── ServerError           5xx  an error on our side

Catch EllipsisError to catch everything this SDK raises. Catch APIError for anything the API answered, and read .status when you care about a code the hierarchy does not name.

What an APIError carries

AttributeValue
statusThe HTTP status.
codeThe API's stable error code, or None when the response carried no envelope.
messageThe human-readable message.
request_idThe id to quote in a support request, when present.
bodyThe parsed response body.

Switch on code, never on message text. The codes are an open vocabulary: new ones appear without a version break, so treat an unrecognized code by its status.

from ellipsis import APIError

try:
    handle.send("keep going")
except APIError as error:
    if error.code == "session_finished":
        handle = client.sessions.run(prompt="keep going")
    else:
        raise

Retries happen first

429, 502, 503, and 504 are retried automatically with backoff before any exception reaches you, max_retries times. A RateLimitError in your code therefore means the retries were already exhausted. Transport failures are retried the same way, so a TransportError means the request never landed after every attempt.

On this page