Client SDK · Reference

Error handling.

Typed error classes, chat error codes, and the SSE stall watchdog.

Every error raised by this SDK derives from MatildaError.

MatildaAPIError

Raised on non-2xx HTTP responses from the API.

Python
class MatildaAPIError(MatildaError):
    status: int         # HTTP status code
    response_text: str  # Raw response body

QuotaExceededError

A MatildaAPIError subclass for HTTP 429 with a structured quota_exceeded body — the daily quota is spent. Carries the quota payload as attributes:

Python
class QuotaExceededError(MatildaAPIError):
    tier: str | None
    messages_used: int | None
    messages_limit: int | None
    tokens_used: int | None
    tokens_limit: int | None
    resets_at: str | None
    upgrade_action: str | None

MatildaStreamError

A terminal error event on the chat SSE stream, surfaced by the text/object helpers. str(err) is f"{code}: {message}".

Python
class MatildaStreamError(MatildaError):
    code: str  # a ChatErrorCode

SafetyReplaceError

Raised by chat.stream_text(), chat.stream_object(), and chat.create_object() when the server replaces the output via a safety filter. str(err) contains the replacement text (or empty string), and categories lists the safety categories that triggered the replacement.

Python
class SafetyReplaceError(MatildaError):
    categories: list[str]

MatildaObjectParseError

Raised by chat.stream_object() and chat.create_object() when the response cannot be parsed as JSON or fails pydantic validation — e.g. when a stream is truncated. raw contains the full response text; cause is the underlying json.loads or pydantic error. See Structured output.

Python
class MatildaObjectParseError(MatildaError):
    raw: str
    cause: BaseException | str

UploadError

Raised when a file upload fails after retries (also used for missing-token upload attempts).

AuthError

Raised by auth flows. The code field is an OAuth error code (e.g. 'invalid_grant', 'authorization_pending', 'expired_token', 'access_denied'). The retryable field distinguishes transient failures (5xx, network) from permanent ones (revoked refresh token).

Python
class AuthError(MatildaError):
    code: str
    retryable: bool

Chat error codes (ChatErrorCode)

These codes are emitted via the ResponseError stream event and appear in MatildaChatResponse.errors. Also available as the CHAT_ERROR_CODES frozenset:

CodeDescription
internal_errorServer-side failure.
upstream_unavailableThe AI model is not responding.
rate_limitedToo many requests.
content_blockedSafety filter blocked the content.
stream_abortedThe stream was interrupted before completion.
deadline_exceededThe response did not finish before the deadline.
context_too_largeThe conversation is too long for the model.
url_read_incompleteA URL the server tried to read did not finish loading.
request_budget_exceededThe request exceeded its server-side budget.
stalledNo SSE events for the configured stall window.
unknownUnclassified error (old server without typed codes).

Stall watchdog

The streaming parser arms an idle-event watchdog. If no SSE event arrives for stall_timeout_ms milliseconds, the stream is considered dead and aborted with a 'stalled' error.

  • Default: 45_000 ms (DEFAULT_STALL_TIMEOUT_MS — 3× the server's 15-second keep-alive ping cadence)
  • Disable: Pass stall_timeout_ms=0 (not recommended — mobile loses background-to-foreground hung-stream recovery)

Error handling example

Python
from matilda_client import (
    MatildaAPIError,
    MatildaClient,
    QuotaExceededError,
    SafetyReplaceError,
)


async def main():
    async with MatildaClient(token="...") as client:
        try:
            text = await client.chat.create_text(input="Hello!")
            print(text)
        except QuotaExceededError as err:
            print(f"Daily quota exceeded — resets at {err.resets_at}.")
        except MatildaAPIError as err:
            if err.status == 401:
                print("Session expired — re-authenticate.")
            elif err.status == 429:
                print("Rate limited — slow down.")
            else:
                print(f"API error {err.status}: {err.response_text}")
        except SafetyReplaceError as err:
            print(f"Safety filter: {', '.join(err.categories)}")