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
import { Lunar, BadRequestError } from "lunar";
const client = new Lunar();
try {
const response = await client.chat.completions.create({
model: "gpt-4o-mini",
messages: [], // Invalid: empty messages
});
} catch (e) {
if (e instanceof BadRequestError) {
console.log(`Bad request: ${e}`); // [400] Invalid request...
console.log(`Status: ${e.statusCode}`); // 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}")
import { Lunar, AuthenticationError } from "lunar";
try {
const client = new Lunar({ apiKey: "invalid-key" });
const response = await client.chat.completions.create({
model: "gpt-4o-mini",
messages: [{ role: "user", content: "Hello" }],
});
} catch (e) {
if (e instanceof AuthenticationError) {
console.log(`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}")
import { PermissionDeniedError } from "lunar";
try {
const response = await client.chat.completions.create({...});
} catch (e) {
if (e instanceof PermissionDeniedError) {
console.log(`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}")
import { NotFoundError } from "lunar";
try {
const response = await client.chat.completions.create({
model: "non-existent-model",
messages: [{ role: "user", content: "Hello" }],
});
} catch (e) {
if (e instanceof NotFoundError) {
console.log(`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}")
import { UnprocessableEntityError } from "lunar";
try {
const response = await client.chat.completions.create({
model: "gpt-4o-mini",
messages: [{ role: "invalid_role", content: "Hello" }],
});
} catch (e) {
if (e instanceof UnprocessableEntityError) {
console.log(`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
import { ChatNotSupportedError } from "lunar";
try {
const response = await client.chat.completions.create({
model: "pureai/some-base-model",
messages: [{ role: "user", content: "Hello" }],
});
} catch (e) {
if (e instanceof ChatNotSupportedError) {
console.log(`Chat not supported: ${e}`);
console.log(`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")
import { RateLimitError } from "lunar";
try {
const response = await client.chat.completions.create({...});
} catch (e) {
if (e instanceof RateLimitError) {
console.log(`Rate limited: ${e}`);
console.log(`Retry after: ${e.retryAfter}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}")
import { ServerError } from "lunar";
try {
const response = await client.chat.completions.create({...});
} catch (e) {
if (e instanceof ServerError) {
console.log(`Server error [${e.statusCode}]: ${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}")
import { ConnectionError } from "lunar";
try {
const response = await client.chat.completions.create({...});
} catch (e) {
if (e instanceof ConnectionError) {
console.log(`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}")
import { TimeoutError } from "lunar";
try {
const response = await client.chat.completions.create({...});
} catch (e) {
if (e instanceof TimeoutError) {
console.log(`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}")
import { Lunar, APIError } from "lunar";
const client = new Lunar();
try {
const response = await client.chat.completions.create({
model: "gpt-4o-mini",
messages: [{ role: "user", content: "Hello!" }],
});
} catch (e) {
if (e instanceof APIError) {
console.log(`API error [${e.statusCode}]: ${e}`);
if (e.responseBody) {
console.log("Details:", e.responseBody);
}
}
}
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}")
import { Lunar, LunarError } from "lunar";
const client = new Lunar();
try {
const response = await client.chat.completions.create({...});
} catch (e) {
if (e instanceof LunarError) {
console.log(`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}")
import {
Lunar,
BadRequestError,
AuthenticationError,
RateLimitError,
ServerError,
ConnectionError,
TimeoutError,
LunarError,
} from "lunar";
const client = new Lunar();
try {
const response = await client.chat.completions.create({
model: "gpt-4o-mini",
messages: [{ role: "user", content: "Hello!" }],
});
} catch (e) {
if (e instanceof BadRequestError) {
// Fix your request parameters
console.log(`Invalid request: ${e}`);
} else if (e instanceof AuthenticationError) {
// Check your API key
console.log(`Auth failed: ${e}`);
} else if (e instanceof RateLimitError) {
// Wait and retry
console.log(`Rate limited, retry after ${e.retryAfter}s`);
} else if (
e instanceof ServerError ||
e instanceof ConnectionError ||
e instanceof TimeoutError
) {
// Temporary issue — retry later
console.log(`Temporary error: ${e}`);
} else if (e instanceof LunarError) {
// Catch-all for any other Lunar error
console.log(`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"]
)
// The SDK tries each model in order.
// Only raises if ALL models fail.
const response = await 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"],
}
)
const client = new Lunar({
apiKey: "pk_live_YOUR_KEY",
fallbacks: {
"gpt-4o-mini": ["claude-3-haiku", "llama-3.1-8b"],
"gpt-4o": ["claude-3-5-sonnet"],
},
});
Exception Properties
APIError
| Property | Type | Description |
|---|
message | str | Error message |
status_code | int | None | HTTP status code |
response_body | dict | None | Full response body from API |
| Property | Type | Description |
|---|
message | string | Error message |
statusCode | number | undefined | HTTP status code |
responseBody | Record<string, unknown> | undefined | Full response body from API |
RateLimitError
| Property | Type | Description |
|---|
retry_after | float | None | Seconds to wait before retrying |
| Property | Type | Description |
|---|
retryAfter | number | undefined | Seconds to wait before retrying |
ChatNotSupportedError
| Property | Type | Description |
|---|
model | str | undefined | The model that doesn’t support chat |
EvaluationError (Python only)
| Property | Type | Description |
|---|
failed_count | int | Number of failed tasks |
total_count | int | Total number of tasks |
last_error | str | None | Last 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
}
}