Errors
Recover from temporary provider failures without retrying requests that need a human or configuration change.
1. Retry only transient failures
Rate limits, timeouts, and temporary provider unavailability may succeed on another attempt or fallback route. Use is_retryable() rather than maintaining your own list, cap the number of attempts, and back off between them.
import time
from plural import (
AuthenticationError,
BudgetExceededError,
PluralError,
is_retryable,
)
for attempt in range(3):
try:
response = client.chat(
model="openai/gpt-5.6-luna",
messages=messages,
)
break
except (AuthenticationError, BudgetExceededError):
raise # fix credentials or budget; retrying cannot help
except PluralError as exc:
if exc.status_code == 402:
raise RuntimeError("add workspace credits") from exc
if not is_retryable(exc) or attempt == 2:
raise
time.sleep(2**attempt)2. Fail fast when the request must change
Authentication, invalid requests, missing models, context length, content filters, and configuration errors are not transient. Surface them with enough context to fix the key, model, prompt, or client setup. A BudgetExceededError means raise the request cap or add workspace credits; repeating the same request cannot help.
3. Preserve the failed attempt
Gateway failures still create usage and production-trace records with an error status. Environment runs close with stop_reason="failure" and persist the failed episode before re-raising when you pass persist_with=client. Keep those traces: they reveal provider instability, broken tools, and scorer exceptions that aggregate metrics alone can hide.
Hosted HTTP status
The gateway returns 401 for a missing or invalid key, 402 for an empty workspace wallet, 429 for rate limits, and 5xx for upstream failures. In the 0.5.1 client, 401 becomes AuthenticationError, 429 becomes RateLimitError, and 5xx becomes ProviderUnavailable. A hosted 402 remains a generic PluralError with status_code == 402. BudgetExceededError is reserved for a local max_cost_usd or price-cap check.