SOLWYN
Reference

Exceptions

Reference for Solwyn SDK exceptions — BudgetExceededError, ProviderUnavailableError, ConfigurationError, and the translation errors

import os
from openai import OpenAI
from solwyn import BudgetExceededError, ConfigurationError, ProviderUnavailableError, Solwyn

try:
    client = Solwyn(
        OpenAI(),
        api_key=os.environ["SOLWYN_API_KEY"],
        budget_mode="hard_deny",
    )
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": "Hello!"}],
    )
except ConfigurationError as e:
    print(f"Bad config: {e.message} (field: {e.field})")
except BudgetExceededError as e:
    print(f"Over budget: ${e.current_usage:.2f} / ${e.budget_limit:.2f}")
except ProviderUnavailableError as e:
    print(f"Provider down: {e.provider}")

Every exception below is importable from the top-level solwyn package. UnsupportedSurfaceError joined them in SDK v0.3.0; on older SDKs it needs the deep import from solwyn.exceptions import UnsupportedSurfaceError.

BudgetExceededError

Raised when a request would exceed the configured budget limit. Only raised in budget_mode="hard_deny" mode. In "alert_only" mode, the SDK logs a warning instead of raising.

When raised

  • Before an LLM call, when the pre-flight budget check returns "denied" and budget_mode="hard_deny".
  • New in 0.3.0: the same check also enforces per-run budget caps — a call denied against the cap on its agent run raises this same exception, with the same attributes.

Attributes

AttributeTypeDescription
project_idstr | NoneProject identifier resolved by the API, if available.
budget_limitfloatConfigured spending cap in dollars.
current_usagefloatAmount already consumed in the current period.
estimated_costfloatEstimated cost of the blocked request.
budget_periodstrBudget window (e.g. "daily", "weekly", "monthly", or "unknown" if not provided by the API).
modestrActive budget mode when the error was raised.

Example

import os
from openai import OpenAI
from solwyn import BudgetExceededError, Solwyn

client = Solwyn(
    OpenAI(),
    api_key=os.environ["SOLWYN_API_KEY"],
    budget_mode="hard_deny",
)

try:
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": "Summarize this document."}],
    )
except BudgetExceededError as e:
    print(f"Budget exhausted: ${e.current_usage:.4f} used of ${e.budget_limit:.2f} cap")
    print(f"Blocked request estimated cost: ${e.estimated_cost:.4f}")
    print(f"Period: {e.budget_period}")
    print(f"Mode: {e.mode}")

client.close()

ProviderUnavailableError

Raised when every provider in the failover chain is unavailable — all circuits open, or the chain is exhausted without a success.

When raised

  • When a provider's circuit breaker is OPEN, the router skips it. If no candidate in the chain can serve the call, the SDK raises this error rather than sending a request that is bound to fail.

Attributes

AttributeTypeDescription
providerstr | NoneThe unavailable provider (e.g. "openai"), or None when the error describes an exhausted chain rather than a single provider.
circuit_statestr | NoneCurrent circuit breaker state ("closed", "open", "half_open"), or None.
attemptedlist[str] | NoneOrdered list of providers the router tried before giving up. Never contains prompt content.

Example

import os
from openai import OpenAI
from solwyn import ProviderUnavailableError, Solwyn

client = Solwyn(
    OpenAI(),
    api_key=os.environ["SOLWYN_API_KEY"],
)

try:
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": "Hello!"}],
    )
except ProviderUnavailableError as e:
    print(f"Provider {e.provider} is unavailable (circuit: {e.circuit_state})")
    print(f"Chain attempted: {e.attempted}")

client.close()

UntranslatableRequestError

Raised when a cross-provider failover hop cannot translate a request from the source provider's dialect into the target's. Raised before any network call, aborting the whole candidate chain. Carries only structural labels describing what could not be translated — never the offending value and never prompt content.

When raised

  • During a cross-provider hop, when a request feature has no equivalent on the target provider (e.g. an OpenAI response_format Anthropic cannot express, a dangling tool call, or a parameter outside the target's accepted range).
  • On hops involving a Bedrock entry, with fixed structural labels such as bedrock.guardrail_config (a safety feature a hop would otherwise silently strip), cache_control (Bedrock cachePoint blocks), missing_max_tokens (inferenceConfig.maxTokens is required for a cross-provider hop — the SDK never invents an output bound), image.opaque_handle (s3Location image sources), and unsupported_kwarg.<key> for any unrecognized keyword.
  • For cross-dialect tool-using streams (e.g. an OpenAI-dialect tool stream failing over to Anthropic) — raised pre-dispatch, before any network call. Same-dialect hops between OpenAI-compatible providers are native passthrough and never raise this.

Attributes

AttributeTypeDescription
sourcestrProvider the request was authored against (e.g. "openai").
targetstrProvider the request was being translated toward (e.g. "anthropic").
featurestrStructural token naming the untranslatable shape (e.g. "response_format", "dangling_tool_call"). Never the offending value or prompt content.

Example

import os
from anthropic import Anthropic
from openai import OpenAI
from solwyn import Solwyn, UntranslatableRequestError

client = Solwyn(
    OpenAI(),
    model="gpt-4o",
    api_key=os.environ["SOLWYN_API_KEY"],
    fallback=[(Anthropic(), "claude-sonnet-4-5", {"max_tokens": 1024})],
)

try:
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": "Hello!"}],
    )
except UntranslatableRequestError as e:
    print(f"Cannot translate {e.feature} from {e.source} to {e.target}")

client.close()

UntranslatableModelError

Raised when a fallback entry has no concrete model configured for its target provider. A model id is a configuration value (not prompt content), so it is safe to surface in the message.

When raised

  • During a cross-provider hop, when the target entry's model is empty or missing — caught structurally before any network call so the chain aborts like every other translation error.

Attributes

AttributeTypeDescription
modelstrThe model identifier that has no mapping.
providerstrThe target provider the model was not configured for.

UnsupportedSurfaceError

Raised when a provider adapter does not serve a requested media surface. New in 0.2.0, alongside the non-text modality surfaces.

Non-chat media surfaces (embeddings, images, audio, video) dispatch through a per-adapter seam; an adapter with no branch for the requested surface raises this instead of letting a spend surface run untracked. Both attributes are configuration values — a surface name and a provider name — never prompt content.

When raised

  • videos.create on an OpenAI-compatible or native Together client — Solwyn's video interception is wired for OpenAI's Sora only. See Surface coverage.
  • Any media surface on a client whose adapter serves no seam for it — embeddings.create on a wrapped Anthropic client, for instance.

Attributes

AttributeTypeDescription
surfacestrThe media surface that was requested (e.g. "embeddings").
providerstrThe provider whose adapter does not serve it.

Import

UnsupportedSurfaceError is exported from the top-level package (SDK v0.3.0+):

from solwyn import UnsupportedSurfaceError

On SDKs before 0.3.0, use the deep import — it still works on current versions:

from solwyn.exceptions import UnsupportedSurfaceError

ConfigurationError

Raised when SDK configuration is invalid or incomplete — almost always at construction time, with one deliberate call-time case (the Bedrock invoke_model guard).

When raised

  • When Solwyn() or AsyncSolwyn() is constructed with an invalid api_key format, a malformed fallback spec (field="fallback_specs"), or an unknown config field.
  • At construction, when a provider= override (constructor argument or 4th fallback-tuple element) names an unknown provider (the message lists the known values), targets a client object that is not a recognized provider SDK client, or mismatches the client's API dialect — an override can only relabel a client within its own dialect (field="provider"). See OpenAI-compatible providers.
  • At call time, when invoke_model or invoke_model_with_response_stream is called on a Bedrock-wrapped client (field="invoke_model"). This is a budget-bypass guard: those surfaces fail loud instead of letting calls run untracked. Use converse() / converse_stream(), or the unwrapped boto3 client for deliberately untracked calls. See Amazon Bedrock.

Attributes

AttributeTypeDescription
fieldstr | NoneConfiguration field that failed validation. May be None for general errors.
messagestrHuman-readable description of the problem.

Example

from openai import OpenAI
from solwyn import ConfigurationError, Solwyn

try:
    client = Solwyn(
        OpenAI(),
        api_key="bad_key_format",
    )
except ConfigurationError as e:
    print(f"Configuration error: {e.message}")
    if e.field:
        print(f"Invalid field: {e.field}")

Exception hierarchy

SolwynError
  +-- BudgetExceededError
  +-- ProviderUnavailableError
  +-- ConfigurationError
  +-- UntranslatableRequestError
  +-- UntranslatableModelError
  +-- UnsupportedSurfaceError

SolwynError is the base class for all Solwyn SDK exceptions. Catch it to handle any error originating from the SDK without distinguishing the specific cause:

from solwyn import SolwynError

try:
    response = client.chat.completions.create(...)
except SolwynError as e:
    # catches every Solwyn-raised error
    ...

Import

Every exception class is exported from the top-level package:

from solwyn import (
    BudgetExceededError,
    ConfigurationError,
    ProviderUnavailableError,
    SolwynError,
    UnsupportedSurfaceError,
    UntranslatableModelError,
    UntranslatableRequestError,
)

UnsupportedSurfaceError was added to the root export in SDK v0.3.0. On earlier versions, import it from solwyn.exceptions instead.

On this page