LLM API Retry and Backoff: Reliable Client Design
Retry only failures that are plausibly transient and only while the request still has time and budget. Respect provider wait guidance, use randomized exponential backoff, prevent duplicate effects, and return a typed terminal outcome when another attempt would increase load without improving the user's result.
Build an explicit retry classification
| Failure class | Default decision | Required check | Terminal outcome |
|---|---|---|---|
| Rate limit | Retry when the deadline and budget permit | Provider wait or reset guidance, remaining quota, and request priority | Deferred, capacity-limited, or alternate eligible route |
| Connection failure before acceptance | Retry cautiously | Whether the request could have reached the provider | Unavailable when acceptance is ambiguous and duplication is unsafe |
| Read timeout or interrupted stream | Depends on product semantics | Partial content, provider completion state, and whether restarting is useful | Partial, cancelled, or unavailable; never concatenate two generations |
| Temporary server failure | Retry a bounded number of times | Provider status contract, outage signal, and global failure rate | Unavailable or policy-compatible fallback |
| Invalid request | Do not retry unchanged | Schema, model support, size, field, and parameter errors | Validation error with actionable detail |
| Authentication or authorization denial | Do not loop | Configuration, identity, permission, tenant, and policy boundary | Denied or configuration error; route to the owner |
| Model refusal or content policy | Do not disguise as transport retry | Product policy and safe alternative behavior | Refusal, clarification, or approved escalation |
Status codes alone are insufficient when providers differ. Keep the classification adapter beside the provider client, version it, and include response headers or documented error type where available. Never parse a human-readable message as the only control signal.
Use backoff, jitter, deadlines, and budgets together
Exponential backoff increases the delay after repeated failure; jitter randomizes it so many clients do not retry in lockstep. The OpenAI Cookbook recommends random exponential backoff for rate-limit errors and warns that unsuccessful requests still contribute to per-minute limits. A loop without a cap can therefore worsen the condition it is trying to recover from.
Apply four boundaries: maximum attempts, maximum elapsed time, the caller's end-to-end deadline, and a shared retry budget for the dependency. Stop when any boundary is exhausted. A request with no time left for a useful answer should not begin another slow attempt merely because its local attempt count is low.
Use provider timing guidance when present, but still add bounded randomization if the contract allows it. Coordinate concurrency and admission so retries do not jump ahead of new work indefinitely. During a broad outage, circuit breaking or load shedding can fail fast while occasional probes test recovery.
Every retry consumes user latency. Include attempts and sleep time in the end-to-end latency trace, and compare recovery benefit with deadline misses and fallback quality.
Protect end-to-end effects, not only API calls
Generating another answer is often safe from a storage perspective, but the surrounding workflow may send a message, charge an account, create a ticket, or invoke a tool. Attach an application operation identifier to consequential work, persist its terminal result, and make repeated delivery return the existing outcome rather than repeat the effect.
Ambiguous failures need special treatment. A connection can drop after the provider or tool accepted work but before the client observed success. If the downstream interface cannot deduplicate, automatic retry may be unsafe. Read the authoritative state first or escalate the ambiguity.
Streaming also changes semantics. If generation stops after partial content reached the user, a fresh attempt is a new generation, not a continuation unless the provider offers explicit resume semantics. Do not append it blindly. Mark the first stream incomplete, restart visibly when appropriate, and run the full output validation contract on the accepted result.
Retry failure cases
- Retry every error: invalid requests and denied access consume quota without becoming valid. Classify first.
- Deterministic delays: a fleet retries at the same intervals and recreates the spike. Add jitter.
- Nested retry multiplication: SDK, service, job, and agent each retry independently. Assign one owner and a shared budget.
- No end-to-end deadline: local attempts continue after the user or upstream job has given up. Propagate cancellation and remaining time.
- Duplicate tool effects: an ambiguous result causes the same action twice. Require idempotency or state readback.
- Fallback hides regression: a backup model returns lower-quality results while transport success looks healthy. Evaluate fallback quality through model-routing gates.
A practical implementation sequence
- Write the provider error map. Translate documented statuses, error types, and timing guidance into retryable, terminal, or ambiguous classes.
- Propagate a deadline. Give each attempt the remaining user or job time and stop before useful completion becomes impossible.
- Apply randomized backoff. Bound minimum and maximum delay, attempts, elapsed time, and shared dependency retries.
- Add end-to-end idempotency. Protect tool calls and durable effects with an operation identifier, terminal record, and state readback.
- Test fault sequences. Inject rate limits, connection loss before and after acceptance, partial streams, server failures, invalid input, denial, cancellation, and outage.
- Instrument the policy. Capture classification, attempt, delay, provider guidance, deadline, fallback, final status, and duplicate prevention in LLM observability.
Decision summary
A reliable retry client answers four questions before another call: is the failure transient, is repetition safe, is there time and budget left, and will another attempt help under current load? If any answer is no or unknown for a consequential effect, stop or inspect state instead of looping.
Primary and official sources
- OpenAI Cookbook: How to Handle Rate Limits — official examples and guidance for random exponential backoff and bounded retries.
- OpenAI API: Rate Limits — official rate-limit concepts, dimensions, headers, and mitigation guidance.