Skip to content

Failure modes

parry follows one rule: a guard rail must never be the reason your call fails, unless failing is the point, as with a budget or a rate limit in "raise" mode.

SituationWhat parry does
Model missing from the pricing tablerecords the call at $0, logs one warning per model, and counts it in unpriced_requests. The budget can’t see that spend, so add a price with set_pricing
Rate limit exhausted"wait": sleeps, then raises parry.RateLimited after max_wait. "raise": raises immediately
Budget reachedraises parry.BudgetExceeded before sending. Cache hits are still served
SQLite file corrupt, locked or read-onlylogs a warning and continues in memory only
Cached entry no longer matches the SDK’s types (after an SDK upgrade)drops the entry and treats the call as a miss
Request contains something that can’t be hashedskips the cache for that call. Everything else still applies
parry’s own bookkeeping raiseslogs a warning. Your response is still returned
SDK not installedinstall() skips that SDK
Retries exhaustedre-raises the SDK’s last exception unchanged
Non-retryable error (400, 401, 403, 404, 422)raised immediately, never retried
create() called with positional argumentspassed straight to the SDK
Stream closed early, or it errorsthe usage seen so far is recorded. Nothing is cached

These calls go straight to the SDK in v0.1:

  • client.chat.completions.parse(...) and client.responses.parse(...)
  • the client.messages.stream(...) and client.beta.chat.completions.stream(...) helpers. create(stream=True) is covered.
  • .with_streaming_response: rate limits and the budget apply, but there is no caching or cost tracking
  • create(stream=True) through .with_raw_response: rate limits and the budget apply, but there is no caching or cost tracking
  • embeddings, batches, files, images and audio