Distiller Client Exceptions¶
NOTE: The following exceptions are available for the SDK version 1.24.0 and later releases.
The AI Refinery SDK includes a robust set of custom exceptions designed to help you handle errors gracefully. Whether dealing with network instability, authentication issues, or database logging errors, these exceptions provide granular control over your application's flow.
All exceptions are exported from air.distiller.exceptions.
Exception Hierarchy¶
Understanding the inheritance structure allows you to catch specific errors or broader categories of failures.
DistillerClientError (Base Exception)
├── AuthenticationError
├── ProjectCreationError
├── ProjectDownloadError
├── ConnectionError
│ ├── UserAlreadyConnectedError
│ ├── ConnectionTimeoutError
│ ├── ConnectionClosedError
│ └── WebSocketError
│ ├── WebSocketSendError
│ └── WebSocketReceiveError
└── DatabaseError
├── HistoryRetrievalError
└── ChatLoggingError
Base Exception¶
DistillerClientError¶
The base class for all Distiller-related errors. You can catch this exception to handle any error raised by the Distiller client.
Attributes:
message(str): A human-readable error description.error_code(str): A unique string code (e.g.,distiller.client.error).status(HTTPStatus): An associated HTTP status code (e.g., 500, 404, 401).extra(dict): A dictionary containing context-specific debugging information (e.g., project names, specific reason codes).
Authentication & Configuration Errors¶
AuthenticationError¶
Status: 401 UNAUTHORIZED
Raised when the API key provided to the client is invalid, expired, or fails validation against the server.
ProjectCreationError¶
Status: 400 BAD REQUEST
Raised when client.create_project() fails. This usually indicates an issue with the project payload or server-side validation.
- Extra Info: Contains
status_code,error_message, and theprojectname.
ProjectDownloadError¶
Status: 404 NOT FOUND
Raised when client.download_project() fails to retrieve a configuration. This often happens if the project name or version does not exist.
- Extra Info: Contains
projectandproject_version.
Connection & Runtime Errors¶
These errors occur during the WebSocket lifecycle (connection, interaction, and disconnection).
ConnectionError¶
Status: 503 SERVICE UNAUTHORIZED
The base class for all network and connectivity issues.
UserAlreadyConnectedError¶
Status: 409 CONFLICT
Raised when attempting to connect with a UUID that is already active in another session. The Distiller enforces a single active connection per UUID.
- Mitigation: Ensure previous sessions are closed or use a unique UUID for the new session.
ConnectionTimeoutError¶
Status: 504 GATEWAY TIMEOUT
Raised in two scenarios:
- Ping Monitor: The client has not received a heartbeat (PING) from the server within the expected interval.
- Idle Timeout: The server closed the connection because the session was idle for too long.
ConnectionClosedError¶
Raised when the WebSocket connection is closed unexpectedly or forcefully, but not due to a timeout or conflict.
WebSocketError¶
Base class for protocol-level errors.
WebSocketSendError: Failed to send a message to the server.WebSocketReceiveError: Failed to receive or parse a message from the server.
Data & History Errors¶
HistoryRetrievalError¶
Raised when client.retrieve_history() fails to fetch past chat logs from the Postgres database.
- Extra Info: Contains specific
account,project, anduuiddetails.
ChatLoggingError¶
Raised when the client fails to log a conversation turn to the database (in _log_chat).
- Extra Info: Contains the
table_nameandrolethat failed to insert.
Usage Examples¶
1. Robust Connection Handling¶
This example demonstrates how to differentiate between a user conflict (which might require user intervention) and a timeout (which might trigger an automatic retry).
import asyncio
from air import AsyncAIRefinery
from air.distiller.exceptions import (
UserAlreadyConnectedError,
ConnectionTimeoutError,
ConnectionError
)
client = AsyncAIRefinery(api_key="...")
async def connect_session():
try:
async with client.distiller(project="my_agent", uuid="user_123") as dc:
await dc.query(query="Hello Agent")
except UserAlreadyConnectedError as e:
print(f"Session Conflict: {e.message}")
print("Please close your other tab or wait a moment.")
except ConnectionTimeoutError as e:
print(f"Connection timed out. Last ping received: {e.extra.get('last_ping')}")
print("Attempting reconnection...")
# Add logic to retry connection
except ConnectionError as e:
print(f"Network error ({e.status}): {e.message}")
2. Debugging with extra Info¶
When developing, the extra dictionary provides valuable context without needing to parse the error message string.
from air.distiller.exceptions import ProjectCreationError
try:
client.distiller.create_project(
project="invalid_project_name@@",
config_path="config.yaml"
)
except ProjectCreationError as e:
print("Creation Failed!")
# Access structured data for logging
print(f"Server responded with: {e.extra.get('status_code')}")
print(f"Server error message: {e.extra.get('error_message')}")