Error Handling

Overview

Every error the SDK throws is a ChatSdkError with structured fields: a machine-readable code, severity level, retryability flag, a user-facing message safe to display in your UI, a developer hint for debugging, and a link to the error knowledge base. You never have to parse error strings.

ChatSdkError structure

import { ChatSdkError } from 'gecx-chat';

// Every ChatSdkError has these fields:
{
  code: string;           // e.g. 'TRANSPORT_CONNECT_FAILED'
  message: string;        // technical error message
  severity: 'low' | 'medium' | 'high' | 'critical';
  retryable: boolean;     // true if the operation can be retried
  userMessage: string;    // safe to show in your UI
  developerHint: string;  // detailed debugging info for your logs
  docsUrl: string;        // link to the error knowledge base entry
  requestId?: string;     // request ID for support escalation
  details?: Record<string, unknown>;  // additional context
  cause?: Error;          // the underlying error, if any
}

Basic error handling

Catch ChatSdkError by checking instanceof:

import { ChatSdkError } from 'gecx-chat';

try {
  await chat.sendText('Where is my order?');
} catch (error) {
  if (error instanceof ChatSdkError) {
    // Show the user-safe message in your UI
    showToast(error.userMessage);

    // Log the developer hint for debugging
    console.error(`[${error.code}] ${error.developerHint}`);

    // Retry if the error is retryable
    if (error.retryable) {
      scheduleRetry();
    }
  } else {
    throw error; // re-throw non-SDK errors
  }
}

Retryable vs non-retryable

Check error.retryable to decide whether to retry an operation.

Retryable errors are temporary. Network blips, server overload, interrupted streams. The SDK itself retries transport-level failures automatically with backoff, but tool-level and send-level retries are up to you.

  • TRANSPORT_CONNECT_FAILED -- connection failed, SDK is retrying
  • STREAM_INTERRUPTED -- stream dropped, SDK is reconnecting
  • SEND_FAILED -- message send failed
  • SERVER_TOOL_HTTP_FAILED -- server tool endpoint unreachable
  • AUTH_EXPIRED -- token expired, SDK is refreshing

Non-retryable errors require a code change or user action. Retrying will produce the same result.

  • CONFIG_INVALID -- bad configuration
  • AUTH_FAILED -- credentials rejected
  • TOOL_VALIDATION_FAILED -- schema mismatch
  • TOOL_NOT_REGISTERED -- unknown tool
  • SESSION_EXPIRED -- session is gone, create a new one

Error categories

PrefixWhat it covers
CONFIG_*Invalid or missing configuration
AUTH_*Authentication and token errors
TOKEN_ENDPOINT_*Token endpoint failures
TRANSPORT_*Connection and transport errors
STREAM_*SSE stream interruptions and parse errors
SESSION_*Session lifecycle (expired, ended, invalid state)
SEND_*Message send failures
TOOL_*Client tool execution errors
SERVER_TOOL_*Server tool HTTP and response errors
NETWORK_*Offline detection and reconnection
GOVERNANCE_*Data governance operations (delete, export, consent)

Displaying errors in UI

Use error.userMessage for anything you show to users. It is written in plain language and never leaks internal details.

Use error.developerHint in your console logs and error tracking. It contains specific remediation steps.

// In a React component
if (chat.error) {
  return (
    <div role="alert">
      <p>{chat.error.userMessage}</p>
      {chat.error.retryable && (
        <button onClick={() => chat.retry()}>Try again</button>
      )}
    </div>
  );
}

Every error also has a docsUrl linking to its entry in the error knowledge base, which includes the full remediation steps.

The gecx doctor CLI

The bundled gecx doctor command diagnoses common integration errors before they reach production. Run it against your local token endpoint:

npx gecx doctor \
  --token-endpoint http://localhost:3000/api/gecx-chat-token \
  --deployment your-deployment-id

A typical run prints one line per check:

✓ token-endpoint  reachable, returns { token, expiresAt, tokenType: 'Bearer' }
✓ deployment      format ok
✗ csp             connect-src missing wss://your-proxy.example.com  →  TRANSPORT_CONNECT_FAILED
✓ env             .env.local present

Each failure resolves to a known ChatSdkError code with a docsUrl so you can jump straight to the fix. Use --help for the full flag list, or npx gecx verify to chain doctor with tsc --noEmit and your test suite into a single CI command. See commands reference for every CLI option.

Error categories at a glance

CategoryCode prefixWhere they originate
Config / authCONFIG_*, AUTH_*, TOKEN_*Client-side, before any network call
Transport / streamTRANSPORT_*, STREAM_*Wire layer
Network / recoveryNETWORK_OFFLINE, RECONNECT_*, RESUME_*, LEADER_LOST, OUTBOX_DROPPEDRecovery FSM
ToolsTOOL_*, SERVER_TOOL_*Tool dispatch
SessionsSESSION_*, SEND_FAILEDSession FSM
UploadsUPLOAD_*, FILE_VALIDATION_FAILED, URL_NOT_ALLOWEDUpload pipeline
VoiceVOICE_* (e.g. VOICE_TOKEN_ENDPOINT_MISSING, VOICE_PROVIDER_UNAVAILABLE)Voice subsystem
MemoryMEMORY_*Memory adapter and interceptor
PermissionsPERMISSION_DENIED, PERMISSION_DISMISSED, PERMISSION_INSECURE_CONTEXT, PERMISSION_PROMPT_BLOCKED, PERMISSION_UNSUPPORTED, PERMISSION_INVALIDATEDPermissionManager
Computer-useCOMPUTER_USE_*Tool dispatch, proxy, session
Agent graphA2A_*, AGENT_GRAPH_*Graph runtime
AnalyticsANALYTICS_SINK_FAILED, ANALYTICS_AGGREGATION_INVALID_WINDOWAnalytics pipeline
Commerce / governanceCOMMERCE_PII_LEAKcommerceGovernance strict mode
HandoffHANDOFF_*Handoff protocol FSM
A2UIA2UI-specific codes — see error knowledge baseSurface manager, renderer, action bridge

See the Error Knowledge Base for severity, retryability, and remediation per code.

What's next

Source: docs/guides/error-handling.md