Error handling.
Run and stream errors, exponential-backoff retries, and partial results after a failure.
MatildaAgentRunError
Thrown on HTTP-level failures (non-2xx response from the server).
class MatildaAgentRunError extends Error {
readonly status: number; // HTTP status code
readonly responseText: string; // Raw response body
}MatildaAgentStreamError
Thrown by run() when the stream emits an error event (unless throwOnStreamError: false). Carries the full AgentRunResult with whatever was collected before the error.
class MatildaAgentStreamError extends Error {
readonly code: ChatErrorCode;
readonly errors: ReadonlyArray<{ code: ChatErrorCode; message: string }>;
readonly result: AgentRunResult;
}import { MatildaAgentStreamError, MatildaAgentRunError } from '@maincode-ai/matilda-agent-sdk';
try {
await runner.run(agent, input);
} catch (err) {
if (err instanceof MatildaAgentStreamError) {
console.log('Stream error code:', err.code);
console.log('Partial output before error:', err.result.finalOutput);
console.log('All errors:', err.errors);
} else if (err instanceof MatildaAgentRunError) {
console.log('HTTP error status:', err.status);
console.log('Response body:', err.responseText);
} else {
throw err;
}
}SafetyReplaceError
Thrown by streamText(), runText(), streamObject(), and runObject() when the server replaces the output via a safety filter. The message property contains the replacement text (or empty string), and categories lists the safety categories.
class SafetyReplaceError extends Error {
readonly categories: string[];
}MatildaObjectParseError
Thrown by streamObject() / runObject() when the response cannot be parsed as JSON or fails zod validation — e.g. a truncated stream (see Structured output). raw holds the full response text; cause is the underlying JSON.parse or zod error. Safety replacement does not surface here — it throws SafetyReplaceError first.
class MatildaObjectParseError extends Error {
readonly raw: string;
readonly cause: unknown;
}AuthError
Thrown by auth flows. The code field is an OAuth error code. The retryable field distinguishes transient failures from permanent ones.
class AuthError extends Error {
readonly code: string;
readonly retryable: boolean;
}Chat error codes (ChatErrorCode)
These codes are emitted via the error stream event and appear in AgentRunResult.errors:
| 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. |
stalled | No SSE events for the configured stall window. |
stream_expired | The durable stream buffer expired (resume path only). |
unknown | Unclassified error (old server without typed codes). |
Stall watchdog
The streaming parser arms an idle-event watchdog. If no SSE event arrives for stallTimeoutMs milliseconds, the stream is considered dead and aborted with a 'stalled' error.
- Default:
45_000ms (DEFAULT_AGENT_STALL_TIMEOUT_MS) - Disable: Pass
stallTimeoutMs: 0inAgentRunOptions(not recommended)
Retry behaviour
The SDK retries retryable errors within a single turn. Retries are controlled by maxRetries (default: 0 — no retries).
Retryable errors:
- HTTP 429 (rate limited), 408 (request timeout), 5xx (server errors)
- Network errors:
UND_ERR_SOCKET,UND_ERR_FETCH_ERROR,ETIMEDOUT,ECONNRESET - SSE stall watchdog (
stallederror code) TimeoutError(but notAbortError)
Retry delay: Exponential backoff with jitter, capped at 30 seconds.
Important: Retries only happen when no text has been yielded to the consumer yet. Retrying past that point would replay text the caller already has.
When a retry occurs, a turn.retrying event is emitted:
for await (const event of runner.stream(agent, input, { maxRetries: 3 })) {
if (event.type === 'turn.retrying') {
console.log(`Retry ${event.attempt}/${event.maxRetries} in ${event.delayMs}ms: ${event.error.message}`);
}
}Error handling example
import {
Runner,
MatildaAgentStreamError,
MatildaAgentRunError,
SafetyReplaceError,
} from '@maincode-ai/matilda-agent-sdk';
const runner = new Runner();
try {
const text = await runner.runText(agent, 'Hello!');
console.log(text);
} catch (err) {
if (err instanceof MatildaAgentStreamError) {
console.error(`Stream error: ${err.code} — ${err.message}`);
console.log('Partial output:', err.result.finalOutput);
} else if (err instanceof MatildaAgentRunError) {
if (err.status === 401) {
console.error('Session expired — re-authenticate.');
} else if (err.status === 429) {
console.error('Rate limited — slow down.');
} else {
console.error(`API error ${err.status}: ${err.responseText}`);
}
} else if (err instanceof SafetyReplaceError) {
console.error(`Safety filter: ${err.categories.join(', ')}`);
} else {
console.error('Unexpected error:', err);
}
}