Repository navigation
Improve rate limit error messages for AI agents #2385
Description
Summary
When the GitHub API returns a rate limit error, the message surfaced to the AI model as a tool result is either missing the retry duration entirely, or buries it inside a noisy raw HTTP string. This makes it hard for agents to know how long to wait before retrying.
All tool errors flow through NewGitHubAPIErrorResponse in pkg/errors/error.go, which formats the tool result as:
<tool message>: <err.Error()>
For a primary rate limit (RateLimitError), the agent sees:
search code: GET https://api.github.com/search/code: 403 API rate limit exceeded for user ID 12345. [rate reset in 47s]
The reset time is present but buried inside a raw HTTP method + URL + status string.
For a secondary (abuse) rate limit (AbuseRateLimitError), the agent sees:
search code: GET https://api.github.com/search/code: 403 You have exceeded a secondary rate limit and have been temporarily blocked from content creation. Please retry your request again later.
The Retry-After duration is completely absent — it is populated in the struct from the HTTP header but dropped by AbuseRateLimitError.Error() (tracked upstream in google/go-github#4180).
Suggested fix
In NewGitHubAPIErrorResponse, use errors.As to detect rate limit error types and return a clean, agent-friendly message:
func NewGitHubAPIErrorResponse(ctx context.Context, message string, resp *github.Response, err error) *mcp.CallToolResult {
apiErr := newGitHubAPIError(message, resp, err)
if ctx != nil {
_, _ = addGitHubAPIErrorToContext(ctx, apiErr)
}
var rateLimitErr *github.RateLimitError
if errors.As(err, &rateLimitErr) {
retryIn := time.Until(rateLimitErr.Rate.Reset.Time).Round(time.Second)
return utils.NewToolResultError(fmt.Sprintf(
"%s: GitHub API rate limit exceeded. Retry after %v.",
message, retryIn))
}
var abuseErr *github.AbuseRateLimitError
if errors.As(err, &abuseErr) {
if abuseErr.RetryAfter != nil {
return utils.NewToolResultError(fmt.Sprintf(
"%s: GitHub secondary rate limit exceeded. Retry after %v.",
message, abuseErr.RetryAfter.Round(time.Second)))
}
return utils.NewToolResultError(fmt.Sprintf(
"%s: GitHub secondary rate limit exceeded. Wait before retrying.",
message))
}
return utils.NewToolResultErrorFromErr(message, err)
}This gives the agent clear, actionable output:
search code: GitHub API rate limit exceeded. Retry after 47s.
search code: GitHub secondary rate limit exceeded. Retry after 60s.
Note: This fix is independent of google/go-github#4180 — it reads
RetryAfterdirectly from the struct rather than relying on.Error(). The go-github fix benefits all other callers of the library.
Note
This issue was drafted with the assistance of GitHub Copilot.
Activity
errors: improve rate limit error messages for AI agents (#2386)