Skip to main content
The Lunar SDK provides a structured exception hierarchy. Errors are categorized into two groups: non-fallback errors (your request is wrong) and fallback-able errors (temporary infrastructure issue — the SDK can try another model).

Exception Hierarchy

LunarError (base)
├── APIError (API-related errors)
│   ├── BadRequestError (400)
│   ├── AuthenticationError (401)
│   ├── PermissionDeniedError (403)
│   ├── NotFoundError (404)
│   ├── UnprocessableEntityError (422)
│   ├── ChatNotSupportedError (400)
│   ├── RateLimitError (429)
│   └── ServerError (5xx)
│       ├── ServiceUnavailableError (503)
│       └── GatewayTimeoutError (504)
├── ConnectionError (network failure)
├── TimeoutError (request timeout)
└── EvaluationError (eval failures) — Python only
Both the Python and TypeScript SDKs export the same exception classes with the same hierarchy.

Non-Fallback Errors

These indicate problems with your request. The SDK will not attempt fallback — retrying with a different model won’t help.

BadRequestError (400)

Invalid request parameters.
from lunar import Lunar, BadRequestError

client = Lunar()

try:
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[]  # Invalid: empty messages
    )
except BadRequestError as e:
    print(f"Bad request: {e}")         # [400] Invalid request...
    print(f"Status: {e.status_code}")  # 400

AuthenticationError (401)

Invalid or missing API key / JWT.
from lunar import Lunar, AuthenticationError

try:
    client = Lunar(api_key="invalid-key")
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": "Hello"}]
    )
except AuthenticationError as e:
    print(f"Auth failed: {e}")
Also raised at initialization if neither api_key/jwt parameter nor LUNAR_API_KEY/LUNAR_JWT environment variable is set.

PermissionDeniedError (403)

Access denied. Your API key doesn’t have permission for this resource.
from lunar import PermissionDeniedError

try:
    response = client.chat.completions.create(...)
except PermissionDeniedError as e:
    print(f"Permission denied: {e}")

NotFoundError (404)

Model or resource not found.
from lunar import NotFoundError

try:
    response = client.chat.completions.create(
        model="non-existent-model",
        messages=[{"role": "user", "content": "Hello"}]
    )
except NotFoundError as e:
    print(f"Not found: {e}")

UnprocessableEntityError (422)

Request validation failed.
from lunar import UnprocessableEntityError

try:
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "invalid_role", "content": "Hello"}]
    )
except UnprocessableEntityError as e:
    print(f"Validation error: {e}")

ChatNotSupportedError (400)

The model doesn’t have a chat template configured. Use /v1/completions instead.
from lunar import ChatNotSupportedError

try:
    response = client.chat.completions.create(
        model="pureai/some-base-model",
        messages=[{"role": "user", "content": "Hello"}]
    )
except ChatNotSupportedError as e:
    print(f"Chat not supported: {e}")
    print(f"Model: {e.model}")
    # Use client.completions.create() instead

Fallback-Triggering Errors

These indicate temporary infrastructure issues. When fallbacks are configured, the SDK automatically tries the next model.

RateLimitError (429)

Rate limit or quota exceeded. Another provider may have capacity.
from lunar import RateLimitError

try:
    response = client.chat.completions.create(...)
except RateLimitError as e:
    print(f"Rate limited: {e}")
    print(f"Retry after: {e.retry_after}s")

ServerError (5xx)

Internal server error from the provider.
from lunar import ServerError

try:
    response = client.chat.completions.create(...)
except ServerError as e:
    print(f"Server error [{e.status_code}]: {e}")

ServiceUnavailableError (503)

Provider temporarily unavailable.

GatewayTimeoutError (504)

Gateway timeout from the provider.

ConnectionError

Network connection failed.
from lunar import ConnectionError

try:
    response = client.chat.completions.create(...)
except ConnectionError as e:
    print(f"Connection error: {e}")

TimeoutError

Request timed out (configurable via timeout parameter, default 60s).
from lunar import TimeoutError

try:
    response = client.chat.completions.create(...)
except TimeoutError as e:
    print(f"Request timeout: {e}")

EvaluationError (Python only)

Raised when an evaluation run fails completely.
from lunar import EvaluationError

try:
    result = client.evals.run(
        name="Test",
        dataset=[...],
        task=my_task,
        scorers=[...]
    )
except EvaluationError as e:
    print(f"Eval failed: {e}")
    print(f"Failed: {e.failed_count}/{e.total_count}")
    print(f"Last error: {e.last_error}")

Error Handling Patterns

Catch All API Errors

from lunar import Lunar, APIError

client = Lunar()

try:
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": "Hello!"}]
    )
except APIError as e:
    print(f"API error [{e.status_code}]: {e}")
    if e.response_body:
        print(f"Details: {e.response_body}")

Catch All Lunar Errors

from lunar import Lunar, LunarError

client = Lunar()

try:
    response = client.chat.completions.create(...)
except LunarError as e:
    print(f"Lunar error: {e}")

Comprehensive Error Handling

from lunar import (
    Lunar,
    BadRequestError,
    AuthenticationError,
    RateLimitError,
    ServerError,
    ConnectionError,
    TimeoutError,
    LunarError,
)

client = Lunar()

try:
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": "Hello!"}]
    )
except BadRequestError as e:
    # Fix your request parameters
    print(f"Invalid request: {e}")
except AuthenticationError as e:
    # Check your API key
    print(f"Auth failed: {e}")
except RateLimitError as e:
    # Wait and retry
    print(f"Rate limited, retry after {e.retry_after}s")
except (ServerError, ConnectionError, TimeoutError) as e:
    # Temporary issue — retry later
    print(f"Temporary error: {e}")
except LunarError as e:
    # Catch-all for any other Lunar error
    print(f"Unexpected error: {e}")

With Fallbacks

When fallbacks are configured, fallback-triggering errors are handled automatically by the SDK:
# The SDK tries each model in order.
# Only raises if ALL models fail.
response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Hello!"}],
    fallbacks=["claude-3-haiku", "llama-3.1-8b"]
)
You can also configure fallbacks globally at client initialization:
client = Lunar(
    api_key="pk_live_YOUR_KEY",
    fallbacks={
        "gpt-4o-mini": ["claude-3-haiku", "llama-3.1-8b"],
        "gpt-4o": ["claude-3-5-sonnet"],
    }
)

Exception Properties

APIError

PropertyTypeDescription
messagestrError message
status_codeint | NoneHTTP status code
response_bodydict | NoneFull response body from API

RateLimitError

PropertyTypeDescription
retry_afterfloat | NoneSeconds to wait before retrying

ChatNotSupportedError

PropertyTypeDescription
modelstr | undefinedThe model that doesn’t support chat

EvaluationError (Python only)

PropertyTypeDescription
failed_countintNumber of failed tasks
total_countintTotal number of tasks
last_errorstr | NoneLast error message

Utility Functions (TypeScript)

The TypeScript SDK also exports helper functions for error classification:
import { isFallbackError, isNonFallbackError, isRetryableError } from "lunar";

try {
  const response = await client.chat.completions.create({...});
} catch (e) {
  if (isFallbackError(e)) {
    // Infrastructure error — safe to retry with another model
  } else if (isNonFallbackError(e)) {
    // Client error — fix your request
  }
}