Skip to main content
Handle errors gracefully with retries, fallbacks, and proper exception handling.

Prerequisites

  • An Auriko API key
  • Python 3.10+ with auriko SDK installed (pip install auriko)
    • OR Node.js 18+ with @auriko/sdk installed (npm install @auriko/sdk)

Error types

All Auriko errors extend AurikoAPIError with these fields:
FieldTypeDescription
messagestrHuman-readable error message
status_codeintHTTP status code
codestrMachine-readable error code
typestr | NoneError category
paramstr | NoneParameter that caused the error
response_headersResponseHeadersResponse headers (includes request_id for support)
The SDK provides 10 specific error classes:
ExceptionStatusWhen
AuthenticationError401Invalid or missing API key
InvalidRequestError400Malformed request, invalid parameter value, or missing required parameter
InsufficientCreditsError402Account has insufficient credits
BudgetExceededError402Budget limit hit (workspace, key, or Bring Your Own Key (BYOK) scope)
ModelNotFoundError404Requested model not in catalog
RateLimitError429Rate limit exceeded
InternalError500Unexpected Auriko server error
ProviderError502/503/504Upstream provider error, timeout, or all providers failed
ProviderAuthError401BYOK key authentication failed at provider
ServiceUnavailableError503Auriko service temporarily unavailable
Some error codes (like missing_required_parameter and no_providers_available) map to shared classes (InvalidRequestError and ProviderError respectively). Any unrecognized error falls to the AurikoAPIError base class via status-code fallback.
See the Python SDK Reference or TypeScript SDK Reference for complete error class fields and hierarchy.

Handle errors

Catch typed exceptions:
import os
from auriko import (
    Client,
    AurikoAPIError,
    AuthenticationError,
    RateLimitError,
    BudgetExceededError,
    ModelNotFoundError,
    ProviderError,
    # Also available: InvalidRequestError, InsufficientCreditsError,
    # InternalError, ProviderAuthError, ServiceUnavailableError
)

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: {e}")

except RateLimitError as e:
    print(f"Rate limited, retry later: {e}")

except BudgetExceededError as e:
    print(f"Budget exceeded: {e}")

except ModelNotFoundError as e:
    print(f"Model not found: {e}")

except ProviderError as e:
    print(f"Provider error: {e}")

except AurikoAPIError as e:
    # Catches all other Auriko errors (InternalError,
    # ServiceUnavailableError, InvalidRequestError, etc.)
    print(f"API error ({e.status_code}): {e}")

Use built-in retries

The SDK automatically retries transient errors with exponential backoff:
SettingValue
Max retries2 (default)
Initial interval500ms
Max interval30 seconds
BackoffExponential (1.5 exponent) + random jitter
Retried status codes429, 500, 502, 503, 504
Connection/timeout errorsRetried
Retry-After headerRespected (overrides backoff when present)
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
)
When the server returns a Retry-After header (common with 429 responses), the SDK uses that value instead of the calculated backoff interval.

Retry manually

For more control, implement custom retry logic:
import os
import time
from auriko import Client, RateLimitError, ProviderError

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 = min(2 ** attempt, 60)  # Cap at 60 seconds
            print(f"Rate limited, waiting {wait_time}s...")
            time.sleep(wait_time)

        except ProviderError as e:
            last_error = e
            wait_time = 2 ** attempt
            print(f"Provider error, retrying in {wait_time}s...")
            time.sleep(wait_time)

    raise last_error

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

Retry asynchronously

Retry with async/await:
import os
import asyncio
from auriko import AsyncClient, RateLimitError, ProviderError

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, ProviderError) as e:
            if attempt == max_retries - 1:
                raise
            wait_time = 2 ** attempt
            await asyncio.sleep(wait_time)
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.

Fall back to another model

Use a cheaper/faster model as fallback:
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:
        # Try primary model
        return client.chat.completions.create(
            model="gpt-4o",
            messages=messages,
            routing={"max_ttft_ms": 200}
        )
    except AurikoAPIError as e:
        print(f"Primary failed ({e}), trying fallback...")

        # Fallback to a different model
        return client.chat.completions.create(
            model="gpt-4o-mini",
            messages=messages
        )

Use circuit breakers

Prevent cascading failures:
import os
from datetime import datetime, timedelta, timezone
from auriko import Client, ProviderError

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 ProviderError as e:
        breaker.record_failure()
        raise

Set timeouts

import os
import httpx
from auriko import Client

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 httpx.TimeoutException:
    print("Request timed out")

Log errors

Log errors for debugging:
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.response_headers.request_id,
        "model": "gpt-4o",
    })
    raise

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():
import os
import openai
from auriko import map_openai_error, RateLimitError, BudgetExceededError

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):
        print(f"Rate limited. Retry after: {auriko_error.response_headers.rate_limit_reset}")
    elif isinstance(auriko_error, BudgetExceededError):
        print(f"Budget exceeded: {auriko_error.message}")
    else:
        raise auriko_error
This gives you access to 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 Switching from OpenAI for migration-focused error mapping.

Best practices

Use built-in retries

Let the SDK handle transient errors automatically

Log errors

Log errors with context for debugging

Set timeouts

Prevent requests from hanging indefinitely

Have fallbacks

Use fallback models for critical paths