Skip to content

errors: improve rate limit error messages for AI agents#2386

Open
danmoseley wants to merge 4 commits intogithub:mainfrom
danmoseley:github-mcp-server-ratelimit
Open

errors: improve rate limit error messages for AI agents#2386
danmoseley wants to merge 4 commits intogithub:mainfrom
danmoseley:github-mcp-server-ratelimit

Conversation

@danmoseley
Copy link
Copy Markdown

When the GitHub API returns a rate limit error, agents currently receive raw Go HTTP error strings:

search code: GET https://api.github.com/search/code: 403 API rate limit exceeded for user ID 12345. [rate reset in 2m59s]

These are hard for agents to reliably parse. Without a clear signal to stop and wait, agents may retry immediately — burning through quota faster — or misread the retry delay and either wait too short (triggering another error) or too long (wasting time).

This PR makes NewGitHubAPIErrorResponse intercept *github.RateLimitError and *github.AbuseRateLimitError and return clean, actionable messages instead:

search code: GitHub API rate limit exceeded. Retry after 2m59s.
create issue: GitHub secondary rate limit exceeded. Retry after 47s.
create issue: GitHub secondary rate limit exceeded. Wait before retrying.

Edge cases handled:

  • Reset time already expired or zero → "Wait before retrying."
  • AbuseRateLimitError.RetryAfter is nil or zero → "Wait before retrying."
  • Wrapped errors (unwrapped via errors.As)

Backward compatibility: The original error is stored in context via addGitHubAPIErrorToContext before the rate-limit check, so any middleware reading from context is unaffected — only the text returned to the MCP client changes.

Fixes #2385.

Note

This PR description was drafted with GitHub Copilot.

When the GitHub API returns a rate limit error, replace the raw Go HTTP
error string with a clean, actionable message so agents know exactly
how long to wait before retrying.

Before:
  search code: GET https://api.github.com/search/code: 403 API rate
  limit exceeded for user ID 12345. [rate reset in 2m59s]

After:
  search code: GitHub API rate limit exceeded. Retry after 2m59s.
  create issue: GitHub secondary rate limit exceeded. Retry after 47s.
  create issue: GitHub secondary rate limit exceeded. Wait before retrying.

Edge cases: expired/zero reset time, nil RetryAfter, and errors
wrapped with errors.As all produce "Wait before retrying." rather
than a negative or confusing duration.

The original error is stored in context via addGitHubAPIErrorToContext
before the rate-limit check, so middleware is unaffected.

Fixes github#2385.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 25, 2026 19:58
@danmoseley danmoseley requested a review from a team as a code owner April 25, 2026 19:58
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR improves agent-facing tool error messages when GitHub API calls hit primary (RateLimitError) or secondary (AbuseRateLimitError) rate limits, replacing noisy raw HTTP error strings with concise “Retry after …” / “Wait before retrying” guidance.

Changes:

  • Add rate-limit specific formatting in NewGitHubAPIErrorResponse using errors.As for wrapped errors.
  • Add unit tests covering primary/secondary rate limit messages, wrapped errors, and edge cases (reset time expired/zero, missing retry-after).
Show a summary per file
File Description
pkg/errors/error.go Adds rate-limit error detection and returns clean, actionable messages while still recording the original error in context.
pkg/errors/error_test.go Adds coverage for the new rate-limit formatting behavior and edge cases.

Copilot's findings

Comments suppressed due to low confidence (1)

pkg/errors/error_test.go:614

  • This wrapped-rate-limit test has the same flakiness risk as the earlier one: expectedRetryIn is calculated after the call, so the rounded value may not match what the function formatted. Consider computing the expected value before invoking NewGitHubAPIErrorResponse or relaxing the assertion to tolerate small timing deltas.
		result := NewGitHubAPIErrorResponse(ctx, "search code", resp, wrappedErr)
		expectedRetryIn := time.Until(resetTime).Round(time.Second)

  • Files reviewed: 2/2 changed files
  • Comments generated: 2

Comment thread pkg/errors/error.go Outdated
Comment thread pkg/errors/error_test.go Outdated
danmoseley and others added 2 commits April 25, 2026 14:15
Compute expectedRetryIn before calling the function under test,
and use larger reset time offsets (20-30 min), so a 1s boundary
during time.Duration.Round cannot cause spurious mismatches.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Reduces repetition in TestNewGitHubAPIErrorResponse_RateLimits subtests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot's findings

  • Files reviewed: 2/2 changed files
  • Comments generated: 3

Comment thread pkg/errors/error.go Outdated
Comment thread pkg/errors/error.go Outdated
Comment thread pkg/errors/error_test.go Outdated
- Primary rate limit: compute time.Until(resetTime) once and check the
  rounded result is >0 before showing 'Retry after X'. This avoids a
  TOCTOU race between the After(time.Now()) guard and the subsequent
  time.Until call, and prevents showing 'Retry after 0s.' when the
  reset time is imminent.

- Secondary rate limit: round RetryAfter first, then check >0.
  Previously, a RetryAfter of e.g. 200ms would pass the >0 guard
  but format as 'Retry after 0s.' after rounding.

- Add tests for both sub-second edge cases.

- Remove UTF-8 BOM accidentally introduced in error_test.go by
  .NET WriteAllText with the default UTF8 encoding.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

Improve rate limit error messages for AI agents

2 participants