Overview
The Avaliar SDK provides a structured error hierarchy so you can catch and handle specific failure modes. Transient errors are retried automatically with exponential backoff, while permanent errors are raised immediately.
Error Hierarchy
All SDK errors inherit from AvaliarError. Catch this base class to handle any Avaliar-related failure, or catch specific subclasses for fine-grained control.
AvaliarError
├── AvaliarAPIError # Server errors (HTTP 500, 503)
├── AvaliarRequestTimeout # Request timed out
├── AvaliarUserError # Invalid input or configuration
├── AvaliarRateLimitError # Rate limit exceeded (HTTP 429)
├── AvaliarAuthError # Authentication failed (HTTP 401)
├── AvaliarNotFoundError # Resource not found (HTTP 404)
├── AvaliarConflictError # Resource conflict (HTTP 409)
├── AvaliarConnectionError # Network connectivity issues
└── PromptBlockedError # Prompt blocked by safety check (blocking mode)
PromptBlockedError
Raised when blocking mode is enabled and a prompt is flagged before reaching the LLM:
from avaliar import traceable, PromptBlockedError
@traceable("llm", model="gpt-4o", provider="openai", blocking=True)
async def generate(messages: list) -> str:
...
try:
result = await generate(messages)
except PromptBlockedError as e:
print(e.reason) # Why the prompt was blocked
print(e.issues) # List of detected issues (may be None)
# Return a safe fallback response
Error Reference
| Error Class | HTTP Status | Description | Retried? |
|---|
AvaliarAPIError | 500, 503 | Server-side error | Yes |
AvaliarRequestTimeout | — | Request exceeded timeout | No |
AvaliarUserError | 400, 422 | Invalid input or configuration | No |
AvaliarRateLimitError | 429 | Too many requests | Yes |
AvaliarAuthError | 401 | Invalid or expired API key | No |
AvaliarNotFoundError | 404 | Resource does not exist | No |
AvaliarConflictError | 409 | Resource already exists or conflict | No |
AvaliarConnectionError | — | Could not reach the API | Yes |
Retry Strategy
The SDK automatically retries transient errors using exponential backoff with jitter. You do not need to implement retry logic yourself.
Retryable Errors
The following error types are retried automatically:
AvaliarConnectionError — network failures and DNS resolution issues
AvaliarAPIError — server errors (HTTP 500, 503)
AvaliarRateLimitError — rate limit responses (HTTP 429)
Backoff Formula
Each retry waits longer than the previous one:delay = 2^attempt + random_jitter(0, 0.5)
| Attempt | Wait time |
|---|
| 1st retry | 1.0–1.5s |
| 2nd retry | 2.0–2.5s |
| 3rd retry | 4.0–4.5s |
Max Retries
The SDK retries up to 3 times by default. After all retries are exhausted, the original error is raised.
Catching Errors
Catch a Specific Error
from avaliar.errors.client_errors import AvaliarAuthError, AvaliarRateLimitError
try:
result = await generate(messages)
except AvaliarAuthError:
print("Invalid API key. Check your AVALIAR_API_KEY environment variable.")
except AvaliarRateLimitError:
print("Rate limited. The SDK retried automatically but the limit persists.")
Catch All Avaliar Errors
from avaliar.errors.client_errors import AvaliarError
try:
result = await generate(messages)
except AvaliarError as e:
print(f"Avaliar SDK error: {e}")
Handle Errors by Category
from avaliar.errors.client_errors import (
AvaliarError,
AvaliarAuthError,
AvaliarUserError,
AvaliarRateLimitError,
AvaliarAPIError,
AvaliarConnectionError,
AvaliarNotFoundError,
AvaliarRequestTimeout,
)
try:
result = await generate(messages)
except AvaliarAuthError:
# Permanent: check your API key
logger.error("Authentication failed. Verify AVALIAR_API_KEY is correct.")
except AvaliarUserError as e:
# Permanent: fix the request
logger.error(f"Invalid request: {e}")
except AvaliarNotFoundError:
# Permanent: the resource does not exist
logger.error("Requested resource was not found.")
except AvaliarRequestTimeout:
# Consider increasing the timeout
logger.warning("Request timed out.")
except (AvaliarAPIError, AvaliarConnectionError, AvaliarRateLimitError) as e:
# Transient: already retried automatically
logger.warning(f"Transient error after retries: {e}")
except AvaliarError as e:
# Catch-all for any other SDK error
logger.error(f"Unexpected Avaliar error: {e}")
Background error handling
Trace submission happens in background threads. By default, errors in background submission are silently handled — they do not crash your application. If you need to observe or log those failures, use the client directly:
from avaliar.client import Client
client = Client()
def on_error(e: Exception):
logger.error(f"Trace submission failed: {e}")
client.thread_request_with_retries(
method="POST",
data=trace_data,
on_error=on_error,
)
Configuration
Timeout Settings
Configure request timeouts through the SDK client:
import os
# Set the request timeout in seconds (default: 30)
os.environ["AVALIAR_REQUEST_TIMEOUT"] = "60"
Non-retryable errors such as AvaliarAuthError and AvaliarUserError are raised immediately. Do not retry these — they indicate a problem that requires a code or configuration change.
In production, catch AvaliarError broadly and log the details. Use specific exception handlers only where you need to take different recovery actions for different failure modes.