> ## Documentation Index
> Fetch the complete documentation index at: https://docs.auriko.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Error Handling

> Handle errors with retries, fallbacks, and typed exceptions

Every error response includes a machine-readable `code`, a canonical `type`, and the `request_id` for support correlation.

## Prerequisites

* An [Auriko API key](https://auriko.ai/signup?redirectTo=%2Fdashboard%3Ftab%3Dapi-keys)
* Python 3.10+ with the OpenAI SDK (`pip install openai`) or the auriko SDK (`pip install auriko`)
  * OR Node.js 18+ with the OpenAI SDK (`npm install openai`) or `@auriko/sdk` (`npm install @auriko/sdk`)

## Error types

All Auriko errors extend `AurikoAPIError`. The envelope is canonical (see [Errors](/api-reference/errors)):

| Field                                       | Type          | Description                                                   |
| ------------------------------------------- | ------------- | ------------------------------------------------------------- |
| `message`                                   | `str`         | Human-readable error message                                  |
| `status_code`                               | `int`         | HTTP status code                                              |
| `code`                                      | `str`         | Machine-readable error code                                   |
| `type`                                      | `str`         | Canonical error type (one of six values)                      |
| `param`                                     | `str \| None` | Parameter that caused the error                               |
| `request_id` / `requestId`                  | `str`         | Value of `x-request-id` on the failing response               |
| `retry_after_seconds` / `retryAfterSeconds` | `int \| None` | `Retry-After` header value (429 / 503 only)                   |
| `doc_url` / `docUrl`                        | `str \| None` | Link to the error's docs page                                 |
| `provider`                                  | `str \| None` | Upstream provider that generated the error, when attributable |

The SDK provides these typed exception classes:

| Exception               | HTTP            | `type`                              |
| ----------------------- | --------------- | ----------------------------------- |
| `BadRequestError`       | 400 / 413 / 422 | `invalid_request_error`             |
| `AuthenticationError`   | 401             | `authentication_error`              |
| `PermissionDeniedError` | 403             | `permission_error`                  |
| `NotFoundError`         | 404             | `not_found_error`                   |
| `ConflictError`         | 409             | `invalid_request_error`             |
| `RateLimitError`        | 429             | `rate_limit_error`                  |
| `InternalServerError`   | 500             | `api_error`                         |
| `APIStatusError`        | 502 / 503 / 504 | `api_error`                         |
| `APIConnectionError`    | —               | network failure before any response |

<Note>
  Dispatch on `type` + HTTP status for exception class, then on `code` for precise handling within a class. Never branch on `message` text; see [Errors](/api-reference/errors#retry-policy) for retry policy by code.
</Note>

See the [Python SDK Reference](/sdk/python-reference#error-classes) or [TypeScript SDK Reference](/sdk/typescript-reference#error-classes) for complete error class fields and hierarchy.

## Handle errors

Catch typed exceptions:

<CodeGroup>
  ```python Python OpenAI theme={null}
  import os
  import openai

  client = openai.OpenAI(
      api_key=os.environ["AURIKO_API_KEY"],
      base_url="https://api.auriko.ai/v1",
  )

  try:
      response = client.chat.completions.create(
          model="gpt-4o",
          messages=[{"role": "user", "content": "Hello!"}],
      )
      print(response.choices[0].message.content)

  except openai.AuthenticationError as e:
      print(f"Check your API key (status={e.status_code})")
  except openai.RateLimitError as e:
      print(f"Rate limited (status={e.status_code})")
  except openai.NotFoundError as e:
      print(f"Not found: {e.message}")
  except openai.BadRequestError as e:
      print(f"Bad request: {e.message}")
  except openai.PermissionDeniedError as e:
      print(f"Not allowed: {e.message}")
  except openai.InternalServerError as e:
      print(f"Server error (status={e.status_code})")
  except openai.APIStatusError as e:
      print(f"API error ({e.status_code}): {e.message}")
  except openai.APIConnectionError as e:
      print(f"Network error: {e}")
  ```

  ```typescript TypeScript OpenAI theme={null}
  import OpenAI from "openai";

  const client = new OpenAI({
      apiKey: process.env.AURIKO_API_KEY,
      baseURL: "https://api.auriko.ai/v1",
  });

  try {
      const response = await client.chat.completions.create({
          model: "gpt-4o",
          messages: [{ role: "user", content: "Hello!" }],
      });
      console.log(response.choices[0].message.content);

  } catch (e) {
      if (e instanceof OpenAI.AuthenticationError) {
          console.log(`Check your API key (status=${e.status})`);
      } else if (e instanceof OpenAI.RateLimitError) {
          console.log(`Rate limited (status=${e.status})`);
      } else if (e instanceof OpenAI.NotFoundError) {
          console.log(`Not found: ${e.message}`);
      } else if (e instanceof OpenAI.BadRequestError) {
          console.log(`Bad request: ${e.message}`);
      } else if (e instanceof OpenAI.PermissionDeniedError) {
          console.log(`Not allowed: ${e.message}`);
      } else if (e instanceof OpenAI.InternalServerError) {
          console.log(`Server error (status=${e.status})`);
      } else if (e instanceof OpenAI.APIConnectionError) {
          console.log(`Network error: ${e.message}`);
      } else if (e instanceof OpenAI.APIError) {
          console.log(`API error (${e.status}): ${e.message}`);
      }
  }
  ```

  ```python Python Auriko theme={null}
  import os
  from auriko import Client
  from auriko.errors import (
      AurikoAPIError,
      APIConnectionError,
      AuthenticationError,
      PermissionDeniedError,
      BadRequestError,
      ConflictError,
      NotFoundError,
      RateLimitError,
      InternalServerError,
      APIStatusError,
  )

  client = Client(
      api_key=os.environ["AURIKO_API_KEY"],
      base_url="https://api.auriko.ai/v1"
  )

  try:
      response = client.chat.completions.create(
          model="gpt-4o",
          messages=[{"role": "user", "content": "Hello!"}]
      )
      print(response.choices[0].message.content)

  except AuthenticationError as e:
      print(f"Check your API key (request_id={e.request_id})")

  except RateLimitError as e:
      print(f"Rate limited, retry after {e.retry_after_seconds}s")

  except NotFoundError as e:
      print(f"Not found: {e.message} (param={e.param})")

  except BadRequestError as e:
      print(f"Bad request: {e.message} (param={e.param})")

  except PermissionDeniedError as e:
      print(f"Not allowed: {e.message} (code={e.code})")

  except ConflictError as e:
      print(f"Conflict: {e.message} (code={e.code})")

  except InternalServerError as e:
      print(f"Server error (request_id={e.request_id})")

  except APIStatusError as e:
      print(f"Upstream error ({e.status_code}): {e.message}")

  except APIConnectionError as e:
      print(f"Network error: {e.message}")

  except AurikoAPIError as e:
      print(f"API error ({e.status_code}): {e.message}")
  ```

  ```typescript TypeScript Auriko theme={null}
  import {
      Client,
      AurikoAPIError,
      APIConnectionError,
      AuthenticationError,
      PermissionDeniedError,
      BadRequestError,
      ConflictError,
      NotFoundError,
      RateLimitError,
      InternalServerError,
      APIStatusError,
  } from "@auriko/sdk";

  const client = new Client({
      apiKey: process.env.AURIKO_API_KEY,
      baseUrl: "https://api.auriko.ai/v1",
  });

  try {
      const response = await client.chat.completions.create({
          model: "gpt-4o",
          messages: [{ role: "user", content: "Hello!" }],
      });
      console.log(response.choices[0].message.content);

  } catch (e) {
      if (e instanceof AuthenticationError) {
          console.log(`Check your API key (requestId=${e.requestId})`);
      } else if (e instanceof RateLimitError) {
          console.log(`Rate limited, retry after ${e.retryAfterSeconds}s`);
      } else if (e instanceof NotFoundError) {
          console.log(`Not found: ${e.message} (param=${e.param})`);
      } else if (e instanceof BadRequestError) {
          console.log(`Bad request: ${e.message} (param=${e.param})`);
      } else if (e instanceof PermissionDeniedError) {
          console.log(`Not allowed: ${e.message} (code=${e.code})`);
      } else if (e instanceof ConflictError) {
          console.log(`Conflict: ${e.message} (code=${e.code})`);
      } else if (e instanceof InternalServerError) {
          console.log(`Server error (requestId=${e.requestId})`);
      } else if (e instanceof APIStatusError) {
          console.log(`Upstream error (${e.statusCode}): ${e.message}`);
      } else if (e instanceof APIConnectionError) {
          console.log(`Network error: ${e.message}`);
      } else if (e instanceof AurikoAPIError) {
          console.log(`API error (${e.statusCode}): ${e.message}`);
      }
  }
  ```
</CodeGroup>

## Use built-in retries

The SDK automatically retries transient errors with exponential backoff:

| Setting                   | Value                                      |
| ------------------------- | ------------------------------------------ |
| Max retries               | 2 (default)                                |
| Initial interval          | 500ms                                      |
| Max interval              | 30 seconds                                 |
| Backoff                   | Exponential (1.5 exponent) + random jitter |
| Retried status codes      | 429, 500, 502, 503, 504                    |
| Connection/timeout errors | Retried                                    |
| `Retry-After` header      | Respected (overrides backoff when present) |

<CodeGroup>
  ```python Python OpenAI theme={null}
  import os
  from openai import OpenAI

  # Default: 2 retries with exponential backoff
  client = OpenAI(
      api_key=os.environ["AURIKO_API_KEY"],
      base_url="https://api.auriko.ai/v1",
  )

  # More retries
  client = OpenAI(
      api_key=os.environ["AURIKO_API_KEY"],
      base_url="https://api.auriko.ai/v1",
      max_retries=5,
  )

  # Disable retries
  client = OpenAI(
      api_key=os.environ["AURIKO_API_KEY"],
      base_url="https://api.auriko.ai/v1",
      max_retries=0,
  )
  ```

  ```typescript TypeScript OpenAI theme={null}
  import OpenAI from "openai";

  // Default: 2 retries with exponential backoff
  const client = new OpenAI({
      apiKey: process.env.AURIKO_API_KEY,
      baseURL: "https://api.auriko.ai/v1",
  });

  // More retries
  const resilientClient = new OpenAI({
      apiKey: process.env.AURIKO_API_KEY,
      baseURL: "https://api.auriko.ai/v1",
      maxRetries: 5,
  });

  // Disable retries
  const noRetryClient = new OpenAI({
      apiKey: process.env.AURIKO_API_KEY,
      baseURL: "https://api.auriko.ai/v1",
      maxRetries: 0,
  });
  ```

  ```python Python Auriko theme={null}
  import os
  from auriko import Client

  # Default: 2 retries with exponential backoff
  client = Client(
      api_key=os.environ["AURIKO_API_KEY"],
      base_url="https://api.auriko.ai/v1"
  )

  # More retries for resilience
  client = Client(
      api_key=os.environ["AURIKO_API_KEY"],
      base_url="https://api.auriko.ai/v1",
      max_retries=5
  )

  # Disable retries entirely
  client = Client(
      api_key=os.environ["AURIKO_API_KEY"],
      base_url="https://api.auriko.ai/v1",
      max_retries=0
  )
  ```

  ```typescript TypeScript Auriko theme={null}
  import { Client } from "@auriko/sdk";

  // Default: 2 retries with exponential backoff
  const client = new Client({
      apiKey: process.env.AURIKO_API_KEY,
      baseUrl: "https://api.auriko.ai/v1",
  });

  // More retries for resilience
  const resilientClient = new Client({
      apiKey: process.env.AURIKO_API_KEY,
      baseUrl: "https://api.auriko.ai/v1",
      maxRetries: 5,
  });

  // Disable retries entirely
  const noRetryClient = new Client({
      apiKey: process.env.AURIKO_API_KEY,
      baseUrl: "https://api.auriko.ai/v1",
      maxRetries: 0,
  });
  ```
</CodeGroup>

<Note>
  When the server returns a `Retry-After` header (common with 429 responses), the SDK uses that value instead of the calculated backoff interval.
</Note>

## Retry manually

For request-level control over backoff or error filtering, implement custom retry logic:

<CodeGroup>
  ```python Python OpenAI theme={null}
  import os
  import time
  import openai

  client = openai.OpenAI(
      api_key=os.environ["AURIKO_API_KEY"],
      base_url="https://api.auriko.ai/v1",
      max_retries=0,
  )

  def make_request_with_retry(messages, max_retries=3):
      last_error = None

      for attempt in range(max_retries):
          try:
              return client.chat.completions.create(
                  model="gpt-4o",
                  messages=messages,
              )
          except openai.RateLimitError as e:
              last_error = e
              retry_after = e.response.headers.get("Retry-After")
              wait_time = float(retry_after) if retry_after else min(2 ** attempt, 60)
              time.sleep(wait_time)

          except openai.APIStatusError as e:
              last_error = e
              retry_after = e.response.headers.get("Retry-After")
              wait_time = float(retry_after) if retry_after else 2 ** attempt
              time.sleep(wait_time)

      raise last_error

  # Usage
  response = make_request_with_retry([{"role": "user", "content": "Hello!"}])
  ```

  ```typescript TypeScript OpenAI theme={null}
  import OpenAI from "openai";

  const client = new OpenAI({
      apiKey: process.env.AURIKO_API_KEY,
      baseURL: "https://api.auriko.ai/v1",
      maxRetries: 0,
  });

  async function makeRequestWithRetry(
      messages: Array<{ role: string; content: string }>,
      maxRetries = 3
  ) {
      let lastError: Error | undefined;

      for (let attempt = 0; attempt < maxRetries; attempt++) {
          try {
              return await client.chat.completions.create({
                  model: "gpt-4o",
                  messages,
              });
          } catch (e) {
              lastError = e as Error;
              if (e instanceof OpenAI.RateLimitError || e instanceof OpenAI.APIError) {
                  const retryAfter = (e as OpenAI.APIError).headers?.["retry-after"];
                  const waitMs = (retryAfter ? parseFloat(retryAfter) : Math.min(2 ** attempt, 60)) * 1000;
                  await new Promise((r) => setTimeout(r, waitMs));
              } else {
                  throw e;
              }
          }
      }

      throw lastError;
  }
  ```

  ```python Python Auriko theme={null}
  import os
  import time
  from auriko import Client
  from auriko.errors import RateLimitError, APIStatusError

  client = Client(
      api_key=os.environ["AURIKO_API_KEY"],
      base_url="https://api.auriko.ai/v1",
      max_retries=0  # Disable auto-retry
  )

  def make_request_with_retry(messages, max_retries=3):
      last_error = None

      for attempt in range(max_retries):
          try:
              return client.chat.completions.create(
                  model="gpt-4o",
                  messages=messages
              )
          except RateLimitError as e:
              last_error = e
              wait_time = e.retry_after_seconds or min(2 ** attempt, 60)
              time.sleep(wait_time)

          except APIStatusError as e:
              last_error = e
              wait_time = e.retry_after_seconds or 2 ** attempt
              time.sleep(wait_time)

      raise last_error

  # Usage
  response = make_request_with_retry([{"role": "user", "content": "Hello!"}])
  ```

  ```typescript TypeScript Auriko theme={null}
  import { Client, RateLimitError, APIStatusError } from "@auriko/sdk";

  const client = new Client({
      apiKey: process.env.AURIKO_API_KEY,
      baseUrl: "https://api.auriko.ai/v1",
      maxRetries: 0, // Disable auto-retry
  });

  async function makeRequestWithRetry(
      messages: Array<{ role: string; content: string }>,
      maxRetries = 3
  ) {
      let lastError: Error | undefined;

      for (let attempt = 0; attempt < maxRetries; attempt++) {
          try {
              return await client.chat.completions.create({
                  model: "gpt-4o",
                  messages,
              });
          } catch (e) {
              lastError = e as Error;
              if (e instanceof RateLimitError || e instanceof APIStatusError) {
                  const waitMs = (e.retryAfterSeconds ?? Math.min(2 ** attempt, 60)) * 1000;
                  await new Promise((r) => setTimeout(r, waitMs));
              } else {
                  throw e;
              }
          }
      }

      throw lastError;
  }
  ```
</CodeGroup>

## Retry asynchronously

Retry with async/await:

<CodeGroup>
  ```python Python OpenAI theme={null}
  import os
  import asyncio
  import openai

  client = openai.AsyncOpenAI(
      api_key=os.environ["AURIKO_API_KEY"],
      base_url="https://api.auriko.ai/v1",
      max_retries=0,
  )

  async def make_request_with_backoff(messages, max_retries=3):
      for attempt in range(max_retries):
          try:
              return await client.chat.completions.create(
                  model="gpt-4o",
                  messages=messages,
              )
          except (openai.RateLimitError, openai.APIStatusError) as e:
              if attempt == max_retries - 1:
                  raise
              retry_after = e.response.headers.get("Retry-After")
              wait_time = float(retry_after) if retry_after else 2 ** attempt
              await asyncio.sleep(wait_time)
  ```

  ```python Python Auriko theme={null}
  import os
  import asyncio
  from auriko import AsyncClient
  from auriko.errors import RateLimitError, APIStatusError

  client = AsyncClient(
      api_key=os.environ["AURIKO_API_KEY"],
      base_url="https://api.auriko.ai/v1",
      max_retries=0
  )

  async def make_request_with_backoff(messages, max_retries=3):
      for attempt in range(max_retries):
          try:
              return await client.chat.completions.create(
                  model="gpt-4o",
                  messages=messages
              )
          except (RateLimitError, APIStatusError) as e:
              if attempt == max_retries - 1:
                  raise
              wait_time = e.retry_after_seconds or 2 ** attempt
              await asyncio.sleep(wait_time)
  ```
</CodeGroup>

TypeScript is inherently async. See the TypeScript tabs in [Retry manually](#retry-manually).

<Note>
  **Side effects and retries:** When using tools or multi-step workflows, consider whether retries are safe. A retried request that triggers a tool call may execute the tool twice. For idempotency-sensitive operations, either disable automatic retries (`max_retries=0`) or implement your own deduplication logic.
</Note>

## Fall back to another model

Catch the error from your primary model and retry with a different one:

<CodeGroup>
  ```python Python OpenAI theme={null}
  import os
  import openai

  client = openai.OpenAI(
      api_key=os.environ["AURIKO_API_KEY"],
      base_url="https://api.auriko.ai/v1",
  )

  def chat_with_fallback(messages):
      try:
          return client.chat.completions.create(
              model="gpt-4o",
              messages=messages,
              extra_body={"gateway": {"routing": {"max_ttft_ms": 1000}}},
          )
      except openai.APIError as e:
          print(f"Primary failed ({e}), trying fallback...")

          return client.chat.completions.create(
              model="gpt-4o-mini",
              messages=messages,
          )
  ```

  ```typescript TypeScript OpenAI theme={null}
  import OpenAI from "openai";

  const client = new OpenAI({
      apiKey: process.env.AURIKO_API_KEY,
      baseURL: "https://api.auriko.ai/v1",
  });

  async function chatWithFallback(messages: any[]) {
      try {
          return await client.chat.completions.create({
              model: "gpt-4o",
              messages,
              gateway: { routing: { max_ttft_ms: 1000 } },
          });
      } catch (e) {
          if (e instanceof OpenAI.APIError) {
              console.log(`Primary failed (${e}), trying fallback...`);
              return await client.chat.completions.create({
                  model: "gpt-4o-mini",
                  messages,
              });
          }
          throw e;
      }
  }
  ```

  ```python Python Auriko theme={null}
  import os
  from auriko import Client, AurikoAPIError

  client = Client(
      api_key=os.environ["AURIKO_API_KEY"],
      base_url="https://api.auriko.ai/v1"
  )

  def chat_with_fallback(messages):
      try:
          return client.chat.completions.create(
              model="gpt-4o",
              messages=messages,
              gateway={"routing": {"max_ttft_ms": 1000}}
          )
      except AurikoAPIError as e:
          print(f"Primary failed ({e}), trying fallback...")

          return client.chat.completions.create(
              model="gpt-4o-mini",
              messages=messages
          )
  ```

  ```typescript TypeScript Auriko theme={null}
  import { Client, AurikoAPIError } from "@auriko/sdk";

  const client = new Client({
      apiKey: process.env.AURIKO_API_KEY,
      baseUrl: "https://api.auriko.ai/v1",
  });

  async function chatWithFallback(messages: any[]) {
      try {
          return await client.chat.completions.create({
              model: "gpt-4o",
              messages,
              gateway: { routing: { max_ttft_ms: 1000 } },
          });
      } catch (e) {
          if (e instanceof AurikoAPIError) {
              console.log(`Primary failed (${e}), trying fallback...`);
              return await client.chat.completions.create({
                  model: "gpt-4o-mini",
                  messages,
              });
          }
          throw e;
      }
  }
  ```
</CodeGroup>

## Use circuit breakers

A circuit breaker stops sending requests after repeated failures and re-tests after a timeout:

<CodeGroup>
  ```python Python OpenAI theme={null}
  import os
  from datetime import datetime, timedelta, timezone
  import openai

  client = openai.OpenAI(
      api_key=os.environ["AURIKO_API_KEY"],
      base_url="https://api.auriko.ai/v1",
  )

  class CircuitBreaker:
      def __init__(self, failure_threshold=5, reset_timeout=60):
          self.failures = 0
          self.failure_threshold = failure_threshold
          self.reset_timeout = reset_timeout
          self.last_failure = None
          self.is_open = False

      def record_failure(self):
          self.failures += 1
          self.last_failure = datetime.now(timezone.utc)
          if self.failures >= self.failure_threshold:
              self.is_open = True

      def record_success(self):
          self.failures = 0
          self.is_open = False

      def can_proceed(self):
          if not self.is_open:
              return True
          if datetime.now(timezone.utc) - self.last_failure > timedelta(seconds=self.reset_timeout):
              self.is_open = False
              return True
          return False

  # Usage
  breaker = CircuitBreaker()

  def safe_request(messages):
      if not breaker.can_proceed():
          raise Exception("Circuit breaker open, try later")

      try:
          response = client.chat.completions.create(
              model="gpt-4o",
              messages=messages,
          )
          breaker.record_success()
          return response
      except openai.APIStatusError as e:
          breaker.record_failure()
          raise
  ```

  ```typescript TypeScript OpenAI theme={null}
  import OpenAI from "openai";

  const client = new OpenAI({
      apiKey: process.env.AURIKO_API_KEY,
      baseURL: "https://api.auriko.ai/v1",
  });

  class CircuitBreaker {
      private failures = 0;
      private lastFailure: Date | null = null;
      private isOpen = false;

      constructor(
          private failureThreshold = 5,
          private resetTimeout = 60_000,
      ) {}

      recordFailure() {
          this.failures++;
          this.lastFailure = new Date();
          if (this.failures >= this.failureThreshold) this.isOpen = true;
      }

      recordSuccess() {
          this.failures = 0;
          this.isOpen = false;
      }

      canProceed(): boolean {
          if (!this.isOpen) return true;
          if (Date.now() - this.lastFailure!.getTime() > this.resetTimeout) {
              this.isOpen = false;
              return true;
          }
          return false;
      }
  }

  const breaker = new CircuitBreaker();

  async function safeRequest(messages: any[]) {
      if (!breaker.canProceed()) throw new Error("Circuit breaker open, try later");

      try {
          const response = await client.chat.completions.create({ model: "gpt-4o", messages });
          breaker.recordSuccess();
          return response;
      } catch (e) {
          if (e instanceof OpenAI.APIError && !(e instanceof OpenAI.APIConnectionError)) {
              breaker.recordFailure();
          }
          throw e;
      }
  }
  ```

  ```python Python Auriko theme={null}
  import os
  from datetime import datetime, timedelta, timezone
  from auriko import Client
  from auriko.errors import APIStatusError

  client = Client(
      api_key=os.environ["AURIKO_API_KEY"],
      base_url="https://api.auriko.ai/v1"
  )

  class CircuitBreaker:
      def __init__(self, failure_threshold=5, reset_timeout=60):
          self.failures = 0
          self.failure_threshold = failure_threshold
          self.reset_timeout = reset_timeout
          self.last_failure = None
          self.is_open = False

      def record_failure(self):
          self.failures += 1
          self.last_failure = datetime.now(timezone.utc)
          if self.failures >= self.failure_threshold:
              self.is_open = True

      def record_success(self):
          self.failures = 0
          self.is_open = False

      def can_proceed(self):
          if not self.is_open:
              return True
          if datetime.now(timezone.utc) - self.last_failure > timedelta(seconds=self.reset_timeout):
              self.is_open = False
              return True
          return False

  # Usage
  breaker = CircuitBreaker()

  def safe_request(messages):
      if not breaker.can_proceed():
          raise Exception("Circuit breaker open, try later")

      try:
          response = client.chat.completions.create(
              model="gpt-4o",
              messages=messages
          )
          breaker.record_success()
          return response
      except APIStatusError as e:
          breaker.record_failure()
          raise
  ```

  ```typescript TypeScript Auriko theme={null}
  import { Client, APIStatusError } from "@auriko/sdk";

  const client = new Client({
      apiKey: process.env.AURIKO_API_KEY,
      baseUrl: "https://api.auriko.ai/v1",
  });

  class CircuitBreaker {
      private failures = 0;
      private lastFailure: Date | null = null;
      private isOpen = false;

      constructor(
          private failureThreshold = 5,
          private resetTimeout = 60_000,
      ) {}

      recordFailure() {
          this.failures++;
          this.lastFailure = new Date();
          if (this.failures >= this.failureThreshold) this.isOpen = true;
      }

      recordSuccess() {
          this.failures = 0;
          this.isOpen = false;
      }

      canProceed(): boolean {
          if (!this.isOpen) return true;
          if (Date.now() - this.lastFailure!.getTime() > this.resetTimeout) {
              this.isOpen = false;
              return true;
          }
          return false;
      }
  }

  const breaker = new CircuitBreaker();

  async function safeRequest(messages: any[]) {
      if (!breaker.canProceed()) throw new Error("Circuit breaker open, try later");

      try {
          const response = await client.chat.completions.create({ model: "gpt-4o", messages });
          breaker.recordSuccess();
          return response;
      } catch (e) {
          if (e instanceof APIStatusError) breaker.recordFailure();
          throw e;
      }
  }
  ```
</CodeGroup>

## Set timeouts

<CodeGroup>
  ```python Python OpenAI theme={null}
  import os
  import openai

  client = openai.OpenAI(
      api_key=os.environ["AURIKO_API_KEY"],
      base_url="https://api.auriko.ai/v1",
      timeout=30.0,
  )

  try:
      response = client.chat.completions.create(
          model="gpt-4o",
          messages=[{"role": "user", "content": "Write a long essay..."}],
      )
  except openai.APIConnectionError as e:
      print(f"Connection failed: {e}")
  ```

  ```typescript TypeScript OpenAI theme={null}
  import OpenAI from "openai";

  const client = new OpenAI({
      apiKey: process.env.AURIKO_API_KEY,
      baseURL: "https://api.auriko.ai/v1",
      timeout: 30000,
  });

  try {
      const response = await client.chat.completions.create({
          model: "gpt-4o",
          messages: [{ role: "user", content: "Write a long essay..." }],
      });
  } catch (e) {
      if (e instanceof OpenAI.APIConnectionError) {
          console.log(`Connection failed: ${e.message}`);
      }
  }
  ```

  ```python Python Auriko theme={null}
  import os
  from auriko import Client
  from auriko.errors import APIConnectionError

  client = Client(
      api_key=os.environ["AURIKO_API_KEY"],
      base_url="https://api.auriko.ai/v1",
      timeout=30.0  # 30 second timeout
  )

  try:
      response = client.chat.completions.create(
          model="gpt-4o",
          messages=[{"role": "user", "content": "Write a long essay..."}]
      )
  except APIConnectionError as e:
      print(f"Connection failed: {e.message}")
  ```

  ```typescript TypeScript Auriko theme={null}
  import { Client, APIConnectionError } from "@auriko/sdk";

  const client = new Client({
      apiKey: process.env.AURIKO_API_KEY,
      baseUrl: "https://api.auriko.ai/v1",
      timeout: 30000, // 30 second timeout (ms)
  });

  try {
      const response = await client.chat.completions.create({
          model: "gpt-4o",
          messages: [{ role: "user", content: "Write a long essay..." }],
      });
  } catch (e) {
      if (e instanceof APIConnectionError) {
          console.log(`Connection failed: ${e.message}`);
      }
  }
  ```
</CodeGroup>

## Log errors

Log errors for debugging:

<CodeGroup>
  ```python Python OpenAI theme={null}
  import os
  import logging
  import openai

  logging.basicConfig(level=logging.INFO)
  logger = logging.getLogger(__name__)

  client = openai.OpenAI(
      api_key=os.environ["AURIKO_API_KEY"],
      base_url="https://api.auriko.ai/v1",
  )

  try:
      response = client.chat.completions.create(
          model="gpt-4o",
          messages=[{"role": "user", "content": "Hello!"}],
      )
  except openai.APIStatusError as e:
      logger.exception("Chat completion failed", extra={
          "error_type": type(e).__name__,
          "status_code": e.status_code,
          "request_id": e.response.headers.get("x-request-id"),
          "model": "gpt-4o",
      })
      raise
  ```

  ```typescript TypeScript OpenAI theme={null}
  import OpenAI from "openai";

  const client = new OpenAI({
      apiKey: process.env.AURIKO_API_KEY,
      baseURL: "https://api.auriko.ai/v1",
  });

  try {
      const response = await client.chat.completions.create({
          model: "gpt-4o",
          messages: [{ role: "user", content: "Hello!" }],
      });
  } catch (e) {
      if (e instanceof OpenAI.APIError) {
          console.error("Chat completion failed", {
              error_type: e.constructor.name,
              status_code: e.status,
              request_id: e.request_id,
              model: "gpt-4o",
          });
      }
      throw e;
  }
  ```

  ```python Python Auriko theme={null}
  import os
  import logging
  from auriko import Client, AurikoAPIError

  logging.basicConfig(level=logging.INFO)
  logger = logging.getLogger(__name__)

  client = Client(
      api_key=os.environ["AURIKO_API_KEY"],
      base_url="https://api.auriko.ai/v1"
  )

  try:
      response = client.chat.completions.create(
          model="gpt-4o",
          messages=[{"role": "user", "content": "Hello!"}]
      )
  except AurikoAPIError as e:
      logger.exception("Chat completion failed", extra={
          "error_type": type(e).__name__,
          "status_code": e.status_code,
          "request_id": e.request_id,
          "model": "gpt-4o",
      })
      raise
  ```

  ```typescript TypeScript Auriko theme={null}
  import { Client, AurikoAPIError } from "@auriko/sdk";

  const client = new Client({
      apiKey: process.env.AURIKO_API_KEY,
      baseUrl: "https://api.auriko.ai/v1",
  });

  try {
      const response = await client.chat.completions.create({
          model: "gpt-4o",
          messages: [{ role: "user", content: "Hello!" }],
      });
  } catch (e) {
      if (e instanceof AurikoAPIError) {
          console.error("Chat completion failed", {
              error_type: e.constructor.name,
              status_code: e.statusCode,
              request_id: e.requestId,
              model: "gpt-4o",
          });
      }
      throw e;
  }
  ```
</CodeGroup>

## Map OpenAI SDK errors

If you use the OpenAI SDK directly (with `base_url` pointed at Auriko), you can convert OpenAI errors to typed Auriko errors using `map_openai_error()`:

```python theme={null}
import os
import openai
from auriko import map_openai_error
from auriko.errors import RateLimitError, PermissionDeniedError

client = openai.OpenAI(
    api_key=os.environ["AURIKO_API_KEY"],
    base_url="https://api.auriko.ai/v1"
)

try:
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": "Hello!"}]
    )
except openai.APIStatusError as e:
    auriko_error = map_openai_error(e)
    if isinstance(auriko_error, RateLimitError):
        # budget_exhausted and insufficient_quota surface as RateLimitError too;
        # branch on auriko_error.code for code-level retry decisions.
        print(f"Rate limited. Retry after: {auriko_error.retry_after_seconds}s (code={auriko_error.code})")
    elif isinstance(auriko_error, PermissionDeniedError):
        print(f"Permission denied: {auriko_error.message}")
    else:
        raise auriko_error
```

You get typed error fields (`status_code`, `code`, `response_headers`) and fine-grained `isinstance` checks, even when using the OpenAI client.

`map_openai_error()` is Python-only. TypeScript users should use the Auriko SDK directly for typed errors.

See [OpenAI Compatibility](/openai-compatibility#map-errors) for OpenAI SDK error mapping.
