SOLWYN
Guides

Troubleshooting

Symptom-first index for common Solwyn SDK problems in production

This page is a symptom-first index. Find the symptom you are seeing in your application or logs, then follow the resolution.

My calls are not appearing in the dashboard

The most common cause is the metadata reporter being shut down before its background batch flushes.

Resolution:

  1. Confirm client.close() is called when your application exits, or that you used a context manager (with Solwyn(...) as client: / async with AsyncSolwyn(...) as client:).
  2. Look for reporter.ingest_events_rejected warnings (SDK v0.1.7+). If you see them, your batches are reaching Solwyn Cloud but specific events were refused — usually a model Solwyn cannot price yet. See the next section.
  3. Look for the warning Cloud API budget check failed in your logs. If you see it, the SDK could not reach Solwyn Cloud — check your network and SOLWYN_API_URL value.
  4. Verify your SOLWYN_API_KEY is associated with the project ID you are reporting under. The dashboard shows usage per project.

If using AsyncSolwyn, you must await client.close() (not client.close()).

reporter.ingest_events_rejected warnings in my logs

Solwyn Cloud accepted the metadata batch but refused to record specific events in it — this is not a connectivity failure, and the other events in the batch were recorded normally. Logged at WARNING level by the solwyn.reporter logger, one aggregated line per distinct rejection code and model per batch (SDK v0.1.7+):

reporter.ingest_events_rejected: code=unknown_model model=vendor-x-1 count=2 message=Solwyn does not have pricing for model 'vendor-x-1'. File an issue at https://github.com/solwyn-ai/solwyn-python-sdk/issues or contact support — we typically add new models within 24h.

What the codes mean:

  • unknown_model — Solwyn has no pricing entry for that model identifier. Those events were dropped, so their cost is missing from the dashboard.
  • unknown_service_tier — the event carried a service tier Solwyn Cloud does not recognize, so the cost could not be computed at the correct rate.
  • Rejection codes are server-owned and the set can grow without an SDK release; an unfamiliar code is logged the same way. The message field carries the server's guidance verbatim.

Resolution:

  1. Rejected events are terminal: the SDK logs and drops them, never retries — resubmission would be rejected identically until a pricing entry lands server-side. The corresponding calls stay absent from the dashboard.
  2. For unknown_model, open an issue at github.com/solwyn-ai/solwyn-python-sdk with the model= value from the log line. Pricing lives server-side: once Solwyn adds the entry, subsequent traffic is priced automatically — no SDK upgrade or redeploy on your side. The already-rejected calls are not recovered retroactively.
  3. For unknown_service_tier, include the full log line in the issue — the server's message names the tier it could not match, and support for it is likewise a server-side fix.
  4. No action is needed for the accepted events in the same batch — they are already durable.

For the line-by-line format reference, see Logging.

ConfigurationError: Invalid API key format at construction

Your api_key did not match the required pattern sk_proj_<64 lowercase hex chars>.

Common causes:

  • Trailing whitespace or newline (often from copy-paste). Strip with os.environ["SOLWYN_API_KEY"].strip().
  • Missing sk_proj_ prefix.
  • Using the dashboard's display name instead of the raw key.
  • Quoting the value in your .env file with extra characters.

The error's field attribute is set to "api_key" and the message includes the first 12 characters of what the SDK saw.

Dashboard shows no costs and budget caps aren't enforcing

Your SOLWYN_API_KEY is a read-only key. Solwyn Cloud rejects every SDK write surface — budget checks, usage and metadata reporting, and breaker-state reports — from a read-only key with the same structured permission error. The SDK recognizes that response on its budget-check and reporting paths, and logs it once per process, at ERROR level:

solwyn.configuration_error.read_only_key: the configured API key is read-only; use a full-scope project key for SDK budget enforcement and metadata reporting

After that one log line, the SDK suppresses the repeated generic Cloud-API warnings for the same cause and drops reporting for those requests. Budget checks follow your fail_open setting: on the default fail_open=True they fail open — your provider calls keep working, but enforcement and attribution do not; with fail_open=False the usual local fallback applies and calls can be denied. Detection is exact: only the structured read-only permission response triggers this path; other 401/403 responses surface as the ordinary Cloud API budget check failed warnings below, not this one.

Resolution:

  1. Search application logs (including startup, since this fires once per process) for the solwyn.configuration_error.read_only_key line above.
  2. Swap in a full-scope project key. See API keys.
  3. Redeploy with the new key — budget enforcement and dashboard attribution resume on the next call.

Cloud API budget check failed warnings in my logs

Solwyn Cloud was unreachable for one budget check. This is logged at WARNING level by the solwyn logger.

When to ignore: Single occurrences during transient network issues. With the default fail_open=True, your LLM calls proceeded normally with local tracking.

When to investigate: Persistent failures — every call. Check:

  1. SOLWYN_API_URL is correct (default https://api.solwyn.ai).
  2. The host running your code can reach the API URL (curl -I $SOLWYN_API_URL).
  3. Your API key has not been revoked in the dashboard.

If you set fail_open=False, persistent failures will start denying calls once the local cache expires.

BudgetExceededError raised when I did not expect it

You configured budget_mode="hard_deny" and a call's pre-flight check returned "denied" from Solwyn Cloud.

Diagnose:

  1. Inspect e.budget_limit and e.current_usage on the exception. If current_usage is at or near budget_limit, the budget genuinely is exhausted.
  2. Check the dashboard for the project's current period spend.
  3. Confirm you are looking at the right project — multi-agent setups often have separate projects per agent.

To allow calls through while you investigate, switch to budget_mode="alert_only" temporarily.

My calls keep raising ProviderUnavailableError

The provider's circuit breaker is open and the SDK is refusing to send calls. Look for Circuit breaker opened due to failures in your logs.

Resolution:

  1. The circuit closes automatically after the recovery probe succeeds. With defaults, this is roughly 60 seconds (±20% jitter, so up to 72 seconds) + 2 successful probe calls.
  2. To recover faster, restart the process — circuit-breaker state is per-process and resets on restart.
  3. Investigate why the provider was failing — Solwyn does not catch provider exceptions, so the original errors should be visible in your logs from the calls that opened the circuit.

To require more failures before opening (less aggressive), increase circuit_breaker_failure_threshold. To recover faster, decrease circuit_breaker_recovery_timeout. A same-provider model fallback that fails on both the primary and the fallback model still records only one failure against that provider's breaker — failures are deduplicated per provider within a single request — so with the default threshold of 3, the circuit opens after three failed requests.

If you configure a fallback= chain, ProviderUnavailableError is only raised when every candidate is unavailable — a single provider being down should fail over rather than raise. If it raises with a fallback configured, check e.attempted to see which providers the router tried.

My dashboard shows failover usage I didn't expect

Some calls failed on the requested provider/model and were served by a fallback entry. The dashboard tags these events: is_model_fallback=true for a same-provider model swap, is_provider_fallback=true for a cross-provider hop, with failover_reason and requested_provider / requested_model describing what changed.

Resolution:

  1. Filter the dashboard by is_model_fallback / is_provider_fallback to see how often each kind of failover fires.
  2. Inspect failover_reason (circuit_open, primary_error, model_fallback) and failover_error_class to understand why the primary was bypassed.
  3. Check application logs for the original primary errors — the SDK surfaces them only when the whole chain is exhausted, so successful failovers won't reach your exception handlers.
  4. If failover fires more than expected, fix the underlying primary issue, or shorten the fallback= chain to surface the original errors directly.

A cross-provider call raises UntranslatableRequestError

A failover hop to a different provider could not translate the request shape (for example an OpenAI response_format that has no Anthropic equivalent). The chain aborts before any network call, so no duplicate request is sent.

Resolution:

  1. Read e.feature, e.source, and e.target — they name what could not be translated, structurally (never the value).
  2. Either keep that call's request shape within what every provider in the chain can serve, or drop the cross-provider entry for calls that rely on a provider-specific feature.
  3. UntranslatableModelError means a fallback entry has no model set for its provider — add a concrete model to that tuple.

My async tests hang on shutdown

AsyncSolwyn started a background reporter task that was never closed.

Resolution:

Always use async with or call await client.close():

# Correct
async with AsyncSolwyn(AsyncOpenAI()) as client:
    ...

# Also correct
client = AsyncSolwyn(AsyncOpenAI())
try:
    ...
finally:
    await client.close()

# Wrong — hangs on shutdown
client = AsyncSolwyn(AsyncOpenAI())
# ... no close()

Streaming tokens are not being counted

The provider's stream did not emit usage data, or your code aborted the stream before the usage chunk arrived.

Resolution:

  • For OpenAI: Solwyn injects stream_options={"include_usage": True} automatically. If you pass your own stream_options dict, Solwyn preserves your other keys and force-sets include_usage=True — even an explicit include_usage=False is overridden — so missing usage on a direct OpenAI stream is not caused by stream_options.
  • For OpenAI-compatible providers: Solwyn injects include_usage only where the provider documents support for it. It never injects for xAI, Mistral, Together, Fireworks, Perplexity, OpenRouter, or the generic openai_compatible catch-all — those endpoints reject, deprecate, or simply do not document the parameter, and most deliver usage automatically in the final chunk. If no usage arrives at all, the SDK reports length-based estimated counts flagged token_details.is_estimated=true with a one-time WARNING — counts are present but approximate, not missing. See OpenAI-compatible providers.
  • For Anthropic and Google: usage events are emitted by default — no action needed.
  • For Bedrock: usage arrives in the stream's terminal metadata event. Fully consume result["stream"], or on early abandonment call result["stream"].close() (or use with result["stream"]:) so the reservation settles with the observed usage. A stream that settles at zero tokens after real traffic logs Bedrock stream settled at zero tokens — see Streaming.
  • For early aborts on the other providers: wrap the stream in with stream: (sync) or async with stream: (async) so Solwyn settles with the tokens it observed before the break. See Streaming.

The SDK is logging a lot — how do I quiet it?

All Solwyn log messages are emitted under the solwyn logger. Set its level to ERROR to silence WARNING-level messages:

import logging
logging.getLogger("solwyn").setLevel(logging.ERROR)

For the full list of messages and what each one means, see Logging.

Still stuck?

  • Check the SDK version with from solwyn import __version__; print(__version__) and include it in any bug report.
  • Open an issue at github.com/solwyn-ai/solwyn-python-sdk with the version, the symptom, and any relevant log lines.

On this page