Errors
Every Theazo API error uses the same JSON shape and maps to a standard HTTP status. In the SDK, failures throw a typed TheazoError you can branch on by code — no string-parsing of messages.
Response shape
Errors always come back under a top-level error object. details carries structured context specific to the code, and every error includes a requestId (also returned in the X-Request-Id response header).
{
"error": {
"code": "session_limit_exceeded",
"message": "Session ses_abc has reached its maxAgents limit (3/3)",
"details": {
"sessionId": "ses_abc",
"limit": 3,
"current": 3
},
"requestId": "req_xyz123"
}
}Handling errors in the SDK
Catch TheazoError and read its fields: code, status, message, details, and requestId.
try {
const session = await theazo.sessions.forUser('user_123')
const agent = await session.agents.create({ compute: 'python' })
await agent.run('analyze the latest data')
} catch (err) {
if (err instanceof TheazoError) {
console.log(err.code) // a string, e.g. 'session_limit_exceeded'
console.log(err.status) // HTTP status, e.g. 429
console.log(err.message) // human-readable explanation
console.log(err.details) // structured context, e.g. { sessionId, limit, current }
console.log(err.requestId) // 'req_...' — include this when you contact support
}
throw err
}Standard error codes
These codes are returned across the whole API. Individual endpoints may also return more specific codes (validation like invalid_cron or file_too_large, billing like no_subscription, MCP like mcp_name_conflict). Always branch on err.code as a string and keep a default case rather than assuming the set is closed.
| Code | HTTP | Description |
|---|---|---|
invalid_request | 400 | Missing or invalid parameters in the request body or query. |
unauthorized | 401 | Missing or invalid API key. |
forbidden | 403 | The API key is valid but lacks the required scope or environment. |
not_found | 404 | The requested resource does not exist. |
conflict | 409 | Resource state conflict — e.g. the agent is already running. |
budget_exhausted | 402 | The organization's credit balance or budget is spent. |
rate_limited | 429 | Too many requests. Back off and retry after the Retry-After window. |
session_limit_exceeded | 429 | A session limit was hit (maxAgents, maxCost, …). Retrying won't help. |
internal_error | 500 | An unexpected server error. Safe to retry with backoff. |
provider_error | 502 | An upstream compute or model provider returned an error. |
no_providers_available | 503 | All eligible providers are currently unhealthy. |
Retrying
Retry transient failures with exponential backoff: rate_limited, timeout, provider_error, no_providers_available, and internal_error. Do not retry errors that won't change on their own — invalid_request, unauthorized, forbidden, not_found, conflict, session_limit_exceeded, and budget_exhausted. Fix the request or the account instead.
// Retry only transient failures, with exponential backoff.
const RETRIABLE = new Set([
'rate_limited', 'timeout', 'provider_error', 'no_providers_available', 'internal_error',
])
async function withRetry<T>(fn: () => Promise<T>, tries = 3): Promise<T> {
for (let attempt = 1; ; attempt++) {
try {
return await fn()
} catch (err) {
const retriable = err instanceof TheazoError && RETRIABLE.has(err.code)
if (!retriable || attempt >= tries) throw err
await new Promise((r) => setTimeout(r, 2 ** attempt * 250)) // 500ms, 1s, 2s…
}
}
}
const result = await withRetry(() => agent.run('summarize the quarterly report'))
console.log(result.output)requestId from a failed call when you contact support — it lets us find the exact request in our logs immediately. The SDK also surfaces client-side failures as TheazoError with code connection_error or timeout when a request never reaches the API.