Error Handling
Typed error classes, guards, and the difference between transport errors and tool failures.
The SDK distinguishes two kinds of failure: transport errors (the HTTP call to the platform failed) throw typed exceptions, while tool failures (the action ran but the SaaS returned an error) come back as a ToolResult with success: false.
Transport errors
Non-2xx responses throw a subclass of ProtoboxError:
| Class | HTTP | Notes |
|---|---|---|
ValidationError | 400 | fieldErrors when the API provides them |
AuthenticationError | 401 | bad/missing API key |
AuthorizationError | 403 | key lacks permission |
NotFoundError | 404 | resourceType / resourceId |
ConflictError | 409 | |
RateLimitError | 429 | retryAfter (seconds) from the Retry-After header |
ServerError | 5xx | |
NetworkError | — | connection failed |
TimeoutError | — | request exceeded the timeout |
ConnectionNotReadyError | 409 | connection isn't active yet |
NotImplementedError | 501 | reserved feature (e.g. triggers) |
Every error carries code, statusCode, details, and requestId (for support), and serializes with toJSON().
import { isProtoboxError, RateLimitError } from '@protoboxai/sdk';
try {
await protobox.integrations.list();
} catch (err) {
if (err instanceof RateLimitError) {
await sleep((err.retryAfter ?? 1) * 1000);
} else if (isProtoboxError(err)) {
console.error(err.code, err.statusCode, err.requestId);
}
}Guards: isProtoboxError, isNotFoundError, isValidationError, isAuthenticationError, isConnectionNotReadyError.
Tool failures
execute() resolves (does not throw) with a ToolResult:
interface ToolResult {
success: boolean;
data?: unknown; // the action's output on success
error?: string; // message on failure
authRequired?: boolean; // the end-user hasn't connected this integration
executionId?: string; // for tracing
latencyMs?: number;
}Handle the three outcomes:
const result = await user.execute({ name: 'github.create_issue', arguments });
if (result.authRequired) {
// send the user through connect() — they have no active credential
} else if (!result.success) {
console.error('tool failed:', result.error, 'execution', result.executionId);
} else {
console.log(result.data);
}Inside an adapter loop, tool failures are encoded into the provider's result shape instead — see Framework adapters.