Skip to content

Error Handling

switchboard-ai-sdk surfaces errors explicitly — you always know whether the issue is discovery, auth, timeout, or provider failure.

Direct SDK Errors

Direct SDK calls throw typed errors that you can catch and handle per error type:

ts
import {
  ToolNotFoundError,
  ToolUnavailableError,
  ToolAuthError,
  ProviderExecutionError,
  TimeoutError
} from "switchboard-ai-sdk";

Error Types

Error ClassMeaningWhen It Occurs
ToolNotFoundErrorThe requested provider is not known or not installedInvalid provider ID passed to connect()
ToolUnavailableErrorProvider is installed but currently unreachableProvider CLI found but not responding
ToolAuthErrorProvider requires authentication that hasn't been completedChat called before auth flow completed
ProviderExecutionErrorProvider accepted the request but failed to produce outputProvider CLI error, crashed, or returned malformed output
TimeoutErrorOperation exceeded the specified or default timeouttimeoutMs elapsed without completion

Handling Example

ts
import { connect, ToolAuthError, TimeoutError } from "switchboard-ai-sdk";

async function safeChat(prompt: string) {
  const tool = await connect("codex");

  try {
    const result = await tool.chat(
      { messages: [{ role: "user", content: prompt }] },
      { timeoutMs: 30000 }
    );
    return result.message.content;
  } catch (err) {
    if (err instanceof ToolAuthError) {
      // Guide user through auth
      const authResult = await tool.startAuth();
      console.log("Please run:", authResult.command);
      return null;
    }
    if (err instanceof TimeoutError) {
      console.log("Request timed out. Try a shorter prompt or increase the timeout.");
      return null;
    }
    // ProviderExecutionError, ToolUnavailableError, etc.
    throw err;
  }
}

Error Inheritance

All SDK errors extend Error and carry:

  • message — Human-readable description
  • name — The class name (e.g. "ToolAuthError")
  • Additional fields may be present per error type (provider-specific details)

HTTP Error Responses

When using the HTTP server, errors are translated to JSON error envelopes with HTTP status codes:

Error Envelope Format

json
{
  "error": {
    "code": "tool_not_found",
    "message": "Tool 'unknown' is not supported."
  }
}

Status Code Mapping

HTTP Statuserror.codeSDK Error Class
400invalid_requestValidation error (malformed body, bad config)
401tool_auth_requiredToolAuthError
404tool_not_foundToolNotFoundError
502provider_execution_failedProviderExecutionError
503tool_unavailableToolUnavailableError
504timeoutTimeoutError
500internal_errorUnexpected internal failure

Client-Side Handling

bash
response=$(curl -s -w "\n%{http_code}" -X POST http://127.0.0.1:3000/chat/codex \
  -H "content-type: application/json" \
  -d '{"messages":[{"role":"user","content":"Hi"}]}')

http_code=$(echo "$response" | tail -n1)
body=$(echo "$response" | sed '$d')

case $http_code in
  200) echo "Success: $(echo "$body" | jq -r '.result.message.content')" ;;
  401) echo "Auth required: $(echo "$body" | jq -r '.error.message')" ;;
  503) echo "Tool unavailable: $(echo "$body" | jq -r '.error.message')" ;;
  504) echo "Timeout: $(echo "$body" | jq -r '.error.message')" ;;
  *)   echo "Error: $body" ;;
esac

Best Practices

Always Check Health Before Chat

ts
const tool = await connect("codex");

if (!(await tool.health())) {
  throw new Error("Provider is not healthy");
}

const result = await tool.chat({
  messages: [{ role: "user", content: "..." }]
});

Always Check Auth Before Chat (Agent Providers)

ts
const tool = await connect("codex");

const auth = await tool.checkAuth();

if (auth.authStatus === "unauthenticated") {
  const authStart = await tool.startAuth();
  // Present authStart.instructions to user
  return;
}

const result = await tool.chat({
  messages: [{ role: "user", content: "..." }]
});

Set Reasonable Timeouts

Agent tools (Codex, Claude Code, OpenCode) may take longer than runtime tools (Ollama):

ts
// Agent tools — longer timeout for multi-step reasoning
const agentResult = await codex.chat(input, { timeoutMs: 120000 });

// Runtime tools — shorter timeout for direct model calls
const runtimeResult = await ollama.chat(input, { timeoutMs: 30000 });

Use AbortSignal for User Cancellation

ts
const controller = new AbortController();

// User clicks "Cancel" → abort the request
cancelButton.onclick = () => controller.abort();

const result = await tool.chat(input, { signal: controller.signal });

Released under the MIT License. · llms.txt