Skip to content

fix(claude): state Retry-After in every 429 error message - #7286

Open
shivamhwp wants to merge 1 commit into
router-for-me:devfrom
shivamhwp:fix/claude-error-reset-hint
Open

shivamhwp wants to merge 1 commit into
router-for-me:devfrom
shivamhwp:fix/claude-error-reset-hint

Conversation

@shivamhwp

@shivamhwp shivamhwp commented Nov 6, 2026 •

Copy link
Copy Markdown

Follow-up to #7285 and e458999.

Problem

e458999 states the reset in error.message for cooldown 429s. An upstream 429 that CLIProxyAPI passes through still keeps its delay only in Retry-After. Claude Code ignores that header, so the first rate-limit error a user sees never says when the limit resets. Only later requests, which hit the cooldown, do.

Change

The Claude handler appends (reset after …) to any 429 whose Retry-After is positive, not only to cooldowns:

  • The delay comes from the Retry-After actually written, so the text always matches the header. For cooldowns that is still the trusted local deadline.
  • A message that already contains (reset after is left alone.
  • Non-429 statuses, a zero or missing Retry-After, and direct responses are unchanged.

TestClaudeCooldownLeavesOrdinary429MessageUnchanged asserted the old behavior. It is now TestClaudeOrdinary429MessageStatesPassedThroughRetryAfter and expects the hint. The other cooldown tests pass unchanged.

Verification

  • go test ./sdk/api/handlers/claude/, go vet, gofmt, go build ./cmd/server pass.
  • Manual: a local upstream returning Anthropic's 5h-limit 429 with Retry-After, two requests through this build:
429 Retry-After: 8253  This request would exceed your account's rate limit. Please try again later. (reset after 2h17m33s)
429 Retry-After: 8253  All credentials for model claude-sonnet-4-5-20250929 are cooling down via provider claude (last error: ...) (reset after 2h17m33s)

On dev the first message has no reset time.

🤖 Generated with Claude Code

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 6, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-07T01:40:10.138410Z 754d4db New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

The cooldown 429 already states its reset in error.message, but an upstream
429 that CLIProxyAPI passes through keeps its Retry-After only in the header.
Claude Code ignores that header, so the first rate-limit error never shows
when the limit resets. Append the delay from the Retry-After actually written
to any 429 that does not already carry a reset hint.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shivamhwp
shivamhwp force-pushed the fix/claude-error-reset-hint branch from 1f34ab6 to 754d4db Compare November 7, 2026 01:35
@shivamhwp shivamhwp changed the title fix(claude): state Retry-After in Claude error messages fix(claude): state Retry-After in every 429 error message Nov 7, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 754d4db64d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}
message += " (reset after " + delay + ")"
// Claude Code shows only error.message and ignores Retry-After, so state the delay there too.
if status == http.StatusTooManyRequests && !strings.Contains(message, "(reset after ") {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve the local reset hint when the upstream cause has one

When a cooldown's saved upstream error already contains (reset after ...), for example from an upstream CLIProxyAPI instance, modelCooldownError.Error() embeds that hint inside (last error: ...). This new substring check then suppresses the current local countdown: a response with Retry-After: 60 can show only the stale upstream reset after 5m0s, whereas the previous implementation also appended the correct reset after 1m0s. Claude Code users therefore lose the authoritative recovery time on subsequent cooldown responses. Restrict deduplication to a hint matching the current delay, or retain the local hint for cooldown errors.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant