or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

batches.mdbeta-features.mdclient.mdcompletions.mderrors.mdfiles.mdindex.mdmessages.mdmodels.mdskills.mdstreaming.mdtools.mdtypes.md
tile.json

errors.mddocs/

Error Handling

The Anthropic SDK provides comprehensive error classes for different failure scenarios. All errors extend from the base AnthropicError class and provide detailed information for debugging and recovery.

Error Hierarchy

AnthropicError
├── APIError<TStatus, THeaders, TError>
│   ├── BadRequestError (400)
│   ├── AuthenticationError (401)
│   ├── PermissionDeniedError (403)
│   ├── NotFoundError (404)
│   ├── ConflictError (409)
│   ├── UnprocessableEntityError (422)
│   ├── RateLimitError (429)
│   └── InternalServerError (5xx)
├── APIConnectionError
│   └── APIConnectionTimeoutError
└── APIUserAbortError

Base Error Class

class AnthropicError extends Error {
  readonly name: string;
  readonly message: string;
  readonly cause?: Error;
}

All SDK errors inherit from AnthropicError.

API Errors

class APIError<TStatus = number, THeaders = Headers, TError = any> extends AnthropicError {
  readonly status: TStatus;           // HTTP status code
  readonly headers: THeaders;         // Response headers
  readonly error: TError;             // Error details from API
  readonly requestID: string | null;  // Request ID for debugging
}

Example:

try {
  const message = await client.messages.create({ /* ... */ });
} catch (error) {
  if (error instanceof Anthropic.APIError) {
    console.error('Status:', error.status);
    console.error('Message:', error.message);
    console.error('Request ID:', error.requestID);
    console.error('Error details:', error.error);
  }
}

HTTP Status Errors

BadRequestError (400)

Invalid request parameters or malformed request.

class BadRequestError extends APIError<400> {}

Common Causes:

  • Invalid parameter values
  • Missing required fields
  • Malformed JSON
  • Invalid model name

Example:

try {
  const message = await client.messages.create({
    model: 'invalid-model',
    max_tokens: 1024,
    messages: [{ role: 'user', content: 'Hello' }],
  });
} catch (error) {
  if (error instanceof Anthropic.BadRequestError) {
    console.error('Invalid request:', error.message);
    // "model: invalid-model is not a valid model"
  }
}

AuthenticationError (401)

Authentication failed - invalid or missing API key.

class AuthenticationError extends APIError<401> {}

Common Causes:

  • Missing API key
  • Invalid API key
  • Expired API key

Example:

try {
  const client = new Anthropic({ apiKey: 'invalid-key' });
  await client.messages.create({ /* ... */ });
} catch (error) {
  if (error instanceof Anthropic.AuthenticationError) {
    console.error('Authentication failed');
    // Check API key configuration
  }
}

PermissionDeniedError (403)

Insufficient permissions for the requested operation.

class PermissionDeniedError extends APIError<403> {}

Common Causes:

  • Account doesn't have access to requested feature
  • API key lacks required permissions

Example:

try {
  await client.beta.messages.create({
    betas: ['restricted-feature'],
    /* ... */
  });
} catch (error) {
  if (error instanceof Anthropic.PermissionDeniedError) {
    console.error('Access denied to beta feature');
  }
}

NotFoundError (404)

Requested resource not found.

class NotFoundError extends APIError<404> {}

Common Causes:

  • Invalid resource ID
  • Resource was deleted
  • Typo in endpoint or ID

Example:

try {
  const batch = await client.messages.batches.retrieve('nonexistent-id');
} catch (error) {
  if (error instanceof Anthropic.NotFoundError) {
    console.error('Batch not found');
  }
}

ConflictError (409)

Request conflicts with current state.

class ConflictError extends APIError<409> {}

Common Causes:

  • Duplicate resource creation
  • Conflicting operations

Example:

try {
  await client.beta.skills.create({
    name: 'existing-skill',  // Already exists
    /* ... */
  });
} catch (error) {
  if (error instanceof Anthropic.ConflictError) {
    console.error('Skill already exists');
  }
}

UnprocessableEntityError (422)

Request is syntactically correct but semantically invalid.

class UnprocessableEntityError extends APIError<422> {}

Common Causes:

  • Invalid parameter combination
  • Business logic validation failure

Example:

try {
  await client.messages.create({
    model: 'claude-sonnet-4-5-20250929',
    max_tokens: 1024,
    messages: [
      { role: 'assistant', content: 'Cannot start with assistant' },
    ],
  });
} catch (error) {
  if (error instanceof Anthropic.UnprocessableEntityError) {
    console.error('Invalid message structure');
  }
}

RateLimitError (429)

Rate limit exceeded.

class RateLimitError extends APIError<429> {}

Common Causes:

  • Too many requests in time window
  • Exceeded tokens per minute
  • Exceeded requests per day

Example:

try {
  await client.messages.create({ /* ... */ });
} catch (error) {
  if (error instanceof Anthropic.RateLimitError) {
    console.error('Rate limited');

    // Get retry information from headers
    const retryAfter = error.headers.get('retry-after');
    const resetTime = error.headers.get('x-ratelimit-reset');

    console.log(`Retry after: ${retryAfter} seconds`);
    console.log(`Resets at: ${new Date(parseInt(resetTime) * 1000)}`);

    // Implement backoff
    await new Promise(resolve => setTimeout(resolve, parseInt(retryAfter) * 1000));
  }
}

InternalServerError (5xx)

Server-side error.

class InternalServerError extends APIError<500 | 502 | 503 | 504> {}

Common Causes:

  • Temporary server issues
  • Service overload
  • Gateway errors

Example:

try {
  await client.messages.create({ /* ... */ });
} catch (error) {
  if (error instanceof Anthropic.InternalServerError) {
    console.error('Server error:', error.status);

    // Retry with exponential backoff
    await retryWithBackoff(() => client.messages.create({ /* ... */ }));
  }
}

Network Errors

APIConnectionError

Failed to connect to the API.

class APIConnectionError extends AnthropicError {
  readonly cause?: Error;
}

Common Causes:

  • Network connectivity issues
  • DNS resolution failure
  • Firewall blocking requests

Example:

try {
  await client.messages.create({ /* ... */ });
} catch (error) {
  if (error instanceof Anthropic.APIConnectionError) {
    console.error('Network error:', error.message);
    console.error('Cause:', error.cause);

    // Check network connectivity
    // Retry with exponential backoff
  }
}

APIConnectionTimeoutError

Request timed out.

class APIConnectionTimeoutError extends APIConnectionError {}

Common Causes:

  • Request exceeded timeout
  • Slow network connection
  • Large request/response

Example:

try {
  await client.messages.create(
    {
      model: 'claude-sonnet-4-5-20250929',
      max_tokens: 10000,
      messages: [{ role: 'user', content: 'Long task' }],
    },
    { timeout: 30000 }  // 30 seconds
  );
} catch (error) {
  if (error instanceof Anthropic.APIConnectionTimeoutError) {
    console.error('Request timed out');

    // Use streaming for long requests
    const stream = client.messages.stream({ /* ... */ });
  }
}

APIUserAbortError

User aborted the request.

class APIUserAbortError extends AnthropicError {}

Common Causes:

  • User called stream.abort()
  • AbortController signal triggered
  • Stream break

Example:

const stream = client.messages.stream({ /* ... */ });

// User decides to cancel
setTimeout(() => stream.abort(), 5000);

try {
  await stream.done();
} catch (error) {
  if (error instanceof Anthropic.APIUserAbortError) {
    console.log('User canceled the request');
  }
}

Error Handling Patterns

Basic Try-Catch

try {
  const message = await client.messages.create({ /* ... */ });
  console.log(message.content);
} catch (error) {
  if (error instanceof Anthropic.APIError) {
    console.error(`API Error ${error.status}:`, error.message);
  } else if (error instanceof Anthropic.APIConnectionError) {
    console.error('Connection error:', error.message);
  } else {
    console.error('Unexpected error:', error);
    throw error;
  }
}

Comprehensive Error Handling

async function createMessage(params: Anthropic.MessageCreateParams) {
  try {
    return await client.messages.create(params);
  } catch (error) {
    // HTTP errors
    if (error instanceof Anthropic.BadRequestError) {
      console.error('Invalid request parameters');
      throw new Error('Please check your request parameters');
    }

    if (error instanceof Anthropic.AuthenticationError) {
      console.error('Authentication failed');
      throw new Error('Please check your API key');
    }

    if (error instanceof Anthropic.RateLimitError) {
      const retryAfter = error.headers.get('retry-after');
      console.error(`Rate limited. Retry after ${retryAfter}s`);
      await sleep(parseInt(retryAfter) * 1000);
      return createMessage(params);  // Retry
    }

    if (error instanceof Anthropic.InternalServerError) {
      console.error('Server error, retrying...');
      await sleep(5000);
      return createMessage(params);  // Retry
    }

    // Network errors
    if (error instanceof Anthropic.APIConnectionTimeoutError) {
      console.error('Request timed out');
      throw new Error('Request took too long. Try using streaming.');
    }

    if (error instanceof Anthropic.APIConnectionError) {
      console.error('Network error');
      throw new Error('Cannot reach Anthropic API. Check your connection.');
    }

    // User abort
    if (error instanceof Anthropic.APIUserAbortError) {
      console.log('Request was canceled');
      return null;
    }

    // Unknown error
    console.error('Unexpected error:', error);
    throw error;
  }
}

Retry with Exponential Backoff

async function retryWithBackoff<T>(
  fn: () => Promise<T>,
  maxRetries = 3,
  initialDelay = 1000
): Promise<T> {
  let lastError: Error;

  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await fn();
    } catch (error) {
      lastError = error;

      // Don't retry on client errors (4xx except 429)
      if (
        error instanceof Anthropic.BadRequestError ||
        error instanceof Anthropic.AuthenticationError ||
        error instanceof Anthropic.PermissionDeniedError ||
        error instanceof Anthropic.NotFoundError
      ) {
        throw error;
      }

      // Retry on server errors, network errors, and rate limits
      if (
        error instanceof Anthropic.RateLimitError ||
        error instanceof Anthropic.InternalServerError ||
        error instanceof Anthropic.APIConnectionError
      ) {
        const delay = initialDelay * Math.pow(2, attempt);
        console.log(`Retry attempt ${attempt + 1} after ${delay}ms`);
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }

      // Unknown error
      throw error;
    }
  }

  throw lastError;
}

// Usage
const message = await retryWithBackoff(() =>
  client.messages.create({ /* ... */ })
);

Request ID Logging

try {
  const message = await client.messages.create({ /* ... */ });
} catch (error) {
  if (error instanceof Anthropic.APIError) {
    console.error('Error details:', {
      status: error.status,
      message: error.message,
      requestID: error.requestID,  // Include in support requests
      timestamp: new Date().toISOString(),
    });

    // Log for debugging
    logger.error('Anthropic API error', {
      requestId: error.requestID,
      status: error.status,
      error: error.error,
    });
  }
}

Graceful Degradation

async function getResponse(prompt: string): Promise<string> {
  try {
    // Try with Opus first
    const message = await client.messages.create({
      model: 'claude-opus-4-5-20250514',
      max_tokens: 2048,
      messages: [{ role: 'user', content: prompt }],
    });
    return message.content[0].text;
  } catch (error) {
    if (error instanceof Anthropic.RateLimitError) {
      console.warn('Opus rate limited, falling back to Sonnet');

      // Fall back to Sonnet
      const message = await client.messages.create({
        model: 'claude-sonnet-4-5-20250929',
        max_tokens: 2048,
        messages: [{ role: 'user', content: prompt }],
      });
      return message.content[0].text;
    }

    throw error;
  }
}

Accessing Error Details

Error Object Structure

catch (error) {
  if (error instanceof Anthropic.APIError) {
    // Status code
    console.log(error.status);  // 400, 401, 429, etc.

    // Error message
    console.log(error.message);  // Human-readable message

    // Request ID
    console.log(error.requestID);  // 'req_...'

    // Response headers
    console.log(error.headers.get('x-ratelimit-remaining'));

    // Detailed error from API
    console.log(error.error);  // API error object

    // Stack trace
    console.log(error.stack);

    // Original cause (if wrapped)
    console.log(error.cause);
  }
}

API Error Object

if (error instanceof Anthropic.APIError) {
  const apiError = error.error;

  console.log('Type:', apiError.type);
  console.log('Message:', apiError.message);

  // Error-specific fields
  if (apiError.type === 'invalid_request_error') {
    console.log('Invalid field:', apiError.field);
    console.log('Invalid value:', apiError.value);
  }
}

Best Practices

Specific Error Handling

// ✅ Good: Handle specific errors
try {
  const message = await client.messages.create({ /* ... */ });
} catch (error) {
  if (error instanceof Anthropic.RateLimitError) {
    // Handle rate limiting
  } else if (error instanceof Anthropic.AuthenticationError) {
    // Handle auth issues
  } else if (error instanceof Anthropic.APIError) {
    // Handle other API errors
  } else {
    // Handle unexpected errors
  }
}

// ❌ Bad: Generic catch-all
try {
  const message = await client.messages.create({ /* ... */ });
} catch (error) {
  console.error('Error:', error);  // Not helpful
}

Error Logging

// ✅ Good: Log useful context
try {
  const message = await client.messages.create(params);
} catch (error) {
  if (error instanceof Anthropic.APIError) {
    logger.error('Anthropic API request failed', {
      requestId: error.requestID,
      status: error.status,
      message: error.message,
      params: { model: params.model, max_tokens: params.max_tokens },
      userId: currentUserId,
    });
  }
  throw error;
}

User-Friendly Messages

// ✅ Good: User-friendly error messages
try {
  const message = await client.messages.create({ /* ... */ });
} catch (error) {
  if (error instanceof Anthropic.RateLimitError) {
    return {
      error: 'Too many requests. Please try again in a few moments.',
      retryAfter: error.headers.get('retry-after'),
    };
  } else if (error instanceof Anthropic.APIConnectionError) {
    return {
      error: 'Unable to connect to service. Please check your internet connection.',
    };
  } else {
    return {
      error: 'An unexpected error occurred. Please try again later.',
    };
  }
}

See Also

  • Client Configuration - Timeout and retry settings
  • Messages API - Message creation errors
  • Streaming - Stream error handling
  • Types - Error type definitions