feat: API timeout config, Retry-After header, configurable retry, and 400 transient retry#3214
Open
TheArchitectit wants to merge 4 commits into
Open
Conversation
…e retry - Add TimeoutConfig to HTTP client builder with connect_timeout (30s) and request_timeout (5min) defaults, configurable via CLAW_API_CONNECT_TIMEOUT and CLAW_API_REQUEST_TIMEOUT env vars - Add with_timeout() builder to both AnthropicClient and OpenAiCompatClient for per-client timeout configuration - Parse Retry-After header on 429 responses and use it to override exponential backoff delay when present - Add ApiTimeoutConfig to runtime config with apiTimeout settings in ~/.claw/settings.json (connectTimeout, requestTimeout, maxRetries) - Add retry_after field to ApiError::Api for propagating rate limit backoff hints through the retry pipeline
Some providers/proxies return HTTP 400 with bodies like "no parseable body" or "connection reset" during transient network blips. These are not real bad requests — they're gateway errors wearing a 400 mask. Detect known gateway error phrases in 400 response bodies and mark them as retryable so the existing exponential backoff handles them.
Some OpenAI-compat backends (e.g. glm-5.1-fast) return 400 with "no parseable body" when the request payload is too large to parse, rather than a proper context_length_exceeded error. Without this marker, is_context_window_error() returns false and the auto-compact retry loop never triggers — the user just sees an opaque 400 error. 💘 Generated with Crush Assisted-by: GLM 5.1 FP8 via Crush <crush@charm.land>
… 400 transient retry Cherry-picked from PR ultraworkers#2816 onto current upstream/main, resolving conflicts from PR ultraworkers#3015's merge (which added retry_after to ApiError but some construction sites were missing it). Commits preserved: - ade8539: API timeout config, Retry-After header, configurable retry - TimeoutConfig in HTTP client builder (connect 30s, request 5min) - CLAW_API_CONNECT_TIMEOUT and CLAW_API_REQUEST_TIMEOUT env vars - Retry-After header parsing on 429 responses - ApiTimeoutConfig in runtime config (settings.json) - 8a88343: retry 400 responses with transient gateway error bodies - Detects known gateway phrases in 400 response bodies - Marks them as retryable instead of hard-failing - ed91a61: add 'no parseable body' to CONTEXT_WINDOW_ERROR_MARKERS - Some providers return 400 with 'no parseable body' for oversized requests instead of a proper context_length_exceeded error Commits skipped (already in upstream via PR ultraworkers#3015): - 453ab64: optional id field (already merged) - baa8d1b: HTML detection in streaming (already merged) - 33d2f78: JSON error detection in streaming (already merged) 8 files changed, 299 insertions, 80 deletions
This was referenced Jun 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
PR #2816 has been open but stale since May 25 with merge conflicts and
CHANGES_REQUESTEDstatus. The 6 commits are self-contained and valuable, but could not be rebased because the branch predated critical upstream commits.Solution
Fresh branch from current
upstream/main, cherry-picking only the commits that are NOT already in upstream via PR #3015.Commits preserved (3 of 6)
ade853988a883430ed91a61eCommits skipped (already in upstream via PR #3015)
453ab642baa8d1ba633d2f7892Conflict resolution
Cherry-pick conflicts resolved in:
Features
API Timeout Configuration
Retry-After Header Support
Configurable Retry
400 Transient Gateway Error Retry
Context Window Error Detection
Diff verification
8 files changed, 299 insertions, 80 deletions
No upstream commits are reverted. All 5 critical upstream commits verified present.
Closes #2816