Skip to content

Commit 44aa810

Browse files
danmoseleyCopilot
andcommitted
errors: improve rate limit error messages for AI agents
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 #2385. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 4bded57 commit 44aa810

2 files changed

Lines changed: 686 additions & 462 deletions

File tree

pkg/errors/error.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ package errors
22

33
import (
44
"context"
5+
stderrors "errors"
56
"fmt"
67
"net/http"
8+
"time"
79

810
"github.com/github/github-mcp-server/pkg/utils"
911
"github.com/google/go-github/v82/github"
@@ -159,6 +161,30 @@ func NewGitHubAPIErrorResponse(ctx context.Context, message string, resp *github
159161
if ctx != nil {
160162
_, _ = addGitHubAPIErrorToContext(ctx, apiErr) // Explicitly ignore error for graceful handling
161163
}
164+
165+
var rateLimitErr *github.RateLimitError
166+
if stderrors.As(err, &rateLimitErr) {
167+
resetTime := rateLimitErr.Rate.Reset.Time
168+
if !resetTime.IsZero() && resetTime.After(time.Now()) {
169+
retryIn := time.Until(resetTime).Round(time.Second)
170+
return utils.NewToolResultError(fmt.Sprintf(
171+
"%s: GitHub API rate limit exceeded. Retry after %v.", message, retryIn))
172+
}
173+
return utils.NewToolResultError(fmt.Sprintf(
174+
"%s: GitHub API rate limit exceeded. Wait before retrying.", message))
175+
}
176+
177+
var abuseErr *github.AbuseRateLimitError
178+
if stderrors.As(err, &abuseErr) {
179+
if abuseErr.RetryAfter != nil && *abuseErr.RetryAfter > 0 {
180+
return utils.NewToolResultError(fmt.Sprintf(
181+
"%s: GitHub secondary rate limit exceeded. Retry after %v.",
182+
message, abuseErr.RetryAfter.Round(time.Second)))
183+
}
184+
return utils.NewToolResultError(fmt.Sprintf(
185+
"%s: GitHub secondary rate limit exceeded. Wait before retrying.", message))
186+
}
187+
162188
return utils.NewToolResultErrorFromErr(message, err)
163189
}
164190

0 commit comments

Comments
 (0)