AIR

Exceptions reference

Import: from air.exceptions import ...

Hierarchy

text
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.

python
class ProvidersExhaustedError(AIRError):
    def __init__(self, message: str, attempts: list[tuple[str, ProviderError]]):
        ...
        self.attempts = attempts

attempts 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.

python
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.

python
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

python
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)