Search

Search the documentation

Protobox

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:

ClassHTTPNotes
ValidationError400fieldErrors when the API provides them
AuthenticationError401bad/missing API key
AuthorizationError403key lacks permission
NotFoundError404resourceType / resourceId
ConflictError409
RateLimitError429retryAfter (seconds) from the Retry-After header
ServerError5xx
NetworkErrorconnection failed
TimeoutErrorrequest exceeded the timeout
ConnectionNotReadyError409connection isn't active yet
NotImplementedError501reserved 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.

On this page