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.
class MatildaAPIError(MatildaError):
status: int # HTTP status code
response_text: str # Raw response bodyQuotaExceededError
A MatildaAPIError subclass for HTTP 429 with a structured quota_exceeded body — the daily quota is spent. Carries the quota payload as attributes:
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 | NoneMatildaStreamError
A terminal error event on the chat SSE stream, surfaced by the text/object helpers. str(err) is f"{code}: {message}".
class MatildaStreamError(MatildaError):
code: str # a ChatErrorCodeSafetyReplaceError
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.
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.
class MatildaObjectParseError(MatildaError):
raw: str
cause: BaseException | strUploadError
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).
class AuthError(MatildaError):
code: str
retryable: boolChat 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:
| Code | Description |
|---|---|
internal_error | Server-side failure. |
upstream_unavailable | The AI model is not responding. |
rate_limited | Too many requests. |
content_blocked | Safety filter blocked the content. |
stream_aborted | The stream was interrupted before completion. |
deadline_exceeded | The response did not finish before the deadline. |
context_too_large | The conversation is too long for the model. |
url_read_incomplete | A URL the server tried to read did not finish loading. |
request_budget_exceeded | The request exceeded its server-side budget. |
stalled | No SSE events for the configured stall window. |
unknown | Unclassified 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_000ms (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
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)}")