The OpenClaw retry policy
Per-request channel retries, the model recovery budget, provider pacing hints, and what is never retried
Providers throttle, sockets reset, a stream ends before its last event. OpenClaw’s retry policy decides what happens next, and its three goals are simple: retry per HTTP request rather than per multi-step flow, preserve ordering by retrying only the current step, and never duplicate a non-idempotent operation. Here are the channel defaults, the model recovery budget and how it continues a run, what is excluded from that budget, the SDK cap on long waits, the Discord and Telegram specifics, and the separate budget of the durable outbound queue.
Channel defaults
- Three attempts with ten percent jitter for every channel envelope; a minimum delay of four hundred milliseconds for the shared envelope, Telegram and any channel without an override, and five hundred for Discord sends and REST calls.
- A maximum delay cap of thirty seconds for the shared envelope and Discord sends, and five minutes for Discord REST API calls.
- The Discord Gateway WebSocket reconnect loop is separate: up to fifty reconnect attempts backing off exponentially from two seconds to a thirty-second cap, with no jitter.
- Discord retries rate limits, request timeouts, server errors and transient transport failures such as DNS lookups, connection resets and socket closes, using the platform’s retry-after when present; Telegram retries the same class of transient errors, and HTML or Markdown parse errors are not retried but fall back to plain text on the first attempt. Neither channel’s timings are configurable.
Retry per HTTP request, not per multi-step flow.
The model recovery budget
Agent runs recover from temporary rate limits, overloads and provider failures before showing a terminal error: rate limits receive up to ten total attempts, other transient failures allow eight retries within a ninety-second window, backoff starts around one second, grows exponentially and adds jitter, and provider pacing hints such as retry-after headers or a please-try-again message set the minimum wait even beyond the thirty-second backoff cap. Cancellation and the run deadline still stop recovery. Recovery continues the existing transcript with an instruction to preserve completed work and inspect interrupted actions before repeating them, so a throttle after tool activity or partial output recovers without resubmitting the user’s request; the run shows one transient retry indicator, stays cancellable, and recovered attempts leave no persisted assistant error, only a terminal failure keeps one. In the embedded runtime a model idle timeout after tool activity uses the same recovery when every tool in the latest batch has a recorded result and execution has settled, keeping tools available for the next attempt; a Responses stream that ends before its terminal event also qualifies, even with an unfinished tool call, and partial tool arguments are never executed.
Outside the budget
- Billing failures, authentication errors and provider refusals never use the transient budget, and exhausted subscription, daily, weekly or monthly usage windows go directly to eligible auth-profile or model fallback; a long retry-after alone does not prove a usage window is exhausted, so temporary throttles still honour the provider’s minimum wait. The model failover controller owns the budget and, once it is spent, follows the fallback paths or surfaces the final failure; native harnesses may retry internally first, separately from this continuation budget.
- For SDKs that keep internal retries, such as the Anthropic and OpenAI clients, a retry-after longer than sixty seconds makes OpenClaw inject a header telling the SDK not to retry, so control returns promptly; an environment variable raises the cap or disables it so the SDK sleeps through long waits itself. ChatGPT SSE errors keep the HTTP status and retry-after together so an unfamiliar message stays retryable, and the ChatGPT transport reconnects once for a connection-limit error before streaming.
- The embedded session setting for provider max retries overrides the recovery budget, with zero disabling retries while rate limits stay capped at ten attempts; it is a session setting, not a config-file key, and it does not configure native harness retries.
OpenClaw model failover owns the budget described here and decides what happens when it runs out, and The OpenClaw command queue is where a retried step waits its turn.
Durable outbound delivery
The durable outbound queue has its own delivery-attempt budget. When a delivery uses a producer claim, reservation checks the exact owner and its lease before charging an attempt, an expired or replaced claim does not spend the remaining budget, and recovery can acquire a fresh claim before retrying. Producer leases last sixty seconds and renew every twenty while the owner is active, which tolerates brief Gateway stalls; recovery of a vanished producer waits for its last lease to expire, and lease expiry never erases evidence that a send already started, so those entries still need reconciliation before replay. Retries apply per request, message send, media upload, reaction, poll or sticker, and composite flows never retry completed steps. OpenClaw streaming and chunking covers the sends that this budget protects, and The OpenClaw agent loop the run deadline that stops recovery.
On Diali
On Diali the retry budgets run at their upstream defaults inside the assistant, and the managed model route sits in front of the provider, so a terminal error in the chat is one that outlived the whole budget. Hosted OpenClaw on Diali is the assistant and OpenClaw models and providers covers the providers the budget applies to.
- Per request, current step only, never a duplicate.
- Ten attempts for rate limits, eight in ninety seconds otherwise.
- Billing, auth and refusals go straight to fallback.
Stop reading about it, build one
Set up an agent, pick a channel, and have it working inside the app you already keep open.
