Skip to content

Error Handling

Copy page

Every SDK rejects with typed errors so you can branch on failure mode instead of parsing strings. The client SDK has the richest hierarchy; the server and MCP packages each have a focused error type.

All client errors extend DivinciError, which carries the machine-readable code, the HTTP status, an optional details object, and the requestId for support.

ErrorStatusThrown when
AuthenticationError401Invalid, missing, or expired credentials
ValidationError400Invalid request parameters (see fieldErrors)
RateLimitError429Too many requests (see retryAfter, limit, remaining)
QuotaExceededError429Usage quota for the workspace/release is exhausted
PaymentRequiredError402An x402-priced resource needs payment
NotFoundError404The release, thread, or resource doesn’t exist
NetworkErrorConnection failed (see retryable)
TimeoutErrorThe request exceeded timeout
StreamErrorA streaming response failed mid-flight
import {
DivinciClient,
RateLimitError,
QuotaExceededError,
AuthenticationError,
PaymentRequiredError,
} from "@divinci-ai/client";
try {
await client.chat.send(thread.id, "Hello!", { assistantName: "your-assistant-id" });
} catch (error) {
if (error instanceof RateLimitError) {
// Back off using the server-provided hint
await sleep((error.retryAfter ?? 1) * 1000);
return retry();
}
if (error instanceof QuotaExceededError) {
showUpgradePrompt();
return;
}
if (error instanceof AuthenticationError) {
redirectToLogin();
return;
}
if (error instanceof PaymentRequiredError) {
// amount + payment URL are available on the error
openCheckout(error.getPaymentUrl(), error.getAmountUsd());
return;
}
throw error; // unknown — let it bubble
}

Every DivinciError serializes cleanly for logging:

import { DivinciError } from "@divinci-ai/client";
try {
await client.chat.create();
} catch (error) {
if (error instanceof DivinciError) {
console.error(error.toJSON()); // { code, status, details, requestId, message }
}
}

The server SDK throws ServerApiError for any non-2xx API response. It exposes the same fields — code, status, details, requestId, plus the raw body.

import { ServerApiError } from "@divinci-ai/server";
try {
await divinci.workspaces.get("ws_missing");
} catch (error) {
if (error instanceof ServerApiError) {
if (error.status === 404) {
// handle not found
}
console.error(error.code, error.requestId);
}
}

Paid tool calls throw PaymentRequiredError (carrying paymentDetails) when no valid payment accompanies the request. See MCP x402 Payments for the autopay and manual-retry patterns.

  • NetworkError — retry only if error.retryable is true.
  • RateLimitError — honor retryAfter; use exponential backoff if absent.
  • TimeoutError — safe to retry idempotent reads; be careful retrying sends.
  • AuthenticationError / ValidationError — never retry blindly; fix the cause.

The SDKs already retry transient failures internally up to maxRetries (default 3). Tune it per client via the constructor, or pass skipRetry on an individual request through the underlying HTTP client.