errors: improve rate limit error messages for AI agents#2386
Open
danmoseley wants to merge 4 commits intogithub:mainfrom
Open
errors: improve rate limit error messages for AI agents#2386danmoseley wants to merge 4 commits intogithub:mainfrom
danmoseley wants to merge 4 commits intogithub:mainfrom
Conversation
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>
Contributor
There was a problem hiding this comment.
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
NewGitHubAPIErrorResponseusingerrors.Asfor 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:
expectedRetryInis calculated after the call, so the rounded value may not match what the function formatted. Consider computing the expected value before invokingNewGitHubAPIErrorResponseor 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
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>
ee67105 to
52d8383
Compare
- 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>
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.
When the GitHub API returns a rate limit error, agents currently receive raw Go HTTP error strings:
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
NewGitHubAPIErrorResponseintercept*github.RateLimitErrorand*github.AbuseRateLimitErrorand return clean, actionable messages instead:Edge cases handled:
AbuseRateLimitError.RetryAfteris nil or zero → "Wait before retrying."errors.As)Backward compatibility: The original error is stored in context via
addGitHubAPIErrorToContextbefore 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.