Exceptions reference
Import: from air.exceptions import ...
Hierarchy
AIRError
├── ProviderNotFoundError
├── ProviderAlreadyRegisteredError
├── NoProviderAvailableError
├── ConfigurationError
├── ProvidersExhaustedError
└── ProviderError
├── AuthenticationError
├── QuotaExceededError
├── RateLimitError
├── ProviderAPIError
├── ProviderTimeoutError
└── ProviderResponseError
All of these ultimately derive from AIRError, which derives from the built in Exception.
AIRError
Base class for every exception AIR raises. Catch this to handle any AIR specific error generically.
ProviderNotFoundError
Raised by AIR.get_provider(name) (and therefore by air.chat(...)/Session.chat(...) when an explicit provider= name is not registered) when the requested name has not been registered with add_provider(...).
Not eligible for fallback; it is not a ProviderError and is not raised during the priority/intelligent routing loop itself, only in the explicit selection path.
ProviderAlreadyRegisteredError
Raised by AIR.add_provider(provider, ...) if provider.name is already registered.
NoProviderAvailableError
Raised by air.chat(...) when no provider is named (no ChatRequest.provider, no AIRConfig.default_provider) and no providers have been registered at all.
ConfigurationError
Raised by AIR(...) construction when config.routing is not "priority"/"intelligent", or config.context_optimization is not "off"/"auto".
ProvidersExhaustedError
Raised by air.chat(...) when every candidate provider in the routing loop either failed with a fallback eligible error or was skipped (capacity or exhausted-status skip), and none succeeded.
class ProvidersExhaustedError(AIRError):
def __init__(self, message: str, attempts: list[tuple[str, ProviderError]]):
...
self.attempts = attemptsattempts is a list of (provider_name, exception) tuples, one per provider that was tried or skipped during that call, in the order they were attempted.
from air.exceptions import ProvidersExhaustedError
try:
response = await air.chat("Hello")
except ProvidersExhaustedError as exc:
for name, error in exc.attempts:
print(name, error)ProviderError
Base class for errors raised by provider adapters. Not raised directly; always one of the subclasses below.
class ProviderError(AIRError):
def __init__(self, message, *, provider=None, code=None, retryable=None, status_code=None):
...provider: str | None- the provider name that raised it.code: str | None- a provider specific error code or type string, when available.retryable: bool- whether AIR considers this class of error retryable by default (see per-subclass default below); can be overridden per instance.status_code: int | None- the HTTP status code, when the error came from an HTTP response.
AuthenticationError
default_retryable = False. Raised for invalid/missing API keys, or (for Gemini specifically) some permission-denied responses that are not classified as quota errors. Not in FALLBACK_ERRORS; AIR does not try another provider automatically when this is raised during routing. It propagates to the caller.
QuotaExceededError
default_retryable = False. Raised when a provider reports it is out of credits or quota. Is in FALLBACK_ERRORS; AIR falls back to the next configured provider, and marks the raising provider's health as exhausted (see ../core/fallback.md for the recovery implications of this).
RateLimitError
default_retryable = True. Raised on HTTP 429 style rate limiting. Is in FALLBACK_ERRORS.
ProviderAPIError
default_retryable = False. Raised for other HTTP 400+ responses, and for non-timeout network/connection errors. Is in FALLBACK_ERRORS.
ProviderTimeoutError
default_retryable = True. Raised when a request times out. Is in FALLBACK_ERRORS.
ProviderResponseError
default_retryable = False. Raised when a provider's response is not valid JSON, or does not have the expected shape (missing fields, wrong types). Not in FALLBACK_ERRORS; propagates to the caller rather than triggering fallback, since a malformed response usually indicates an integration bug rather than a transient outage.
Minimal handling example
from air.exceptions import (
AuthenticationError,
ProvidersExhaustedError,
ProviderResponseError,
)
try:
response = await air.chat("Hello")
except AuthenticationError:
# bad or missing API key for the directly selected provider; fix configuration
raise
except ProviderResponseError:
# the directly selected provider returned something AIR could not parse
raise
except ProvidersExhaustedError as exc:
# every configured provider failed or was skipped
for name, error in exc.attempts:
print(name, error)