Title: Improve rate limit error messages for AI agents · Issue #2385 · github/github-mcp-server · GitHub
Open Graph Title: Improve rate limit error messages for AI agents · Issue #2385 · github/github-mcp-server
X Title: Improve rate limit error messages for AI agents · Issue #2385 · github/github-mcp-server
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 kn...
Open Graph 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 str...
X 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 str...
Opengraph URL: https://github.com/github/github-mcp-server/issues/2385
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Improve rate limit error messages for AI agents","articleBody":"### Summary\n\nWhen 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.\n\nAll tool errors flow through `NewGitHubAPIErrorResponse` in `pkg/errors/error.go`, which formats the tool result as:\n\n```\n\u003ctool message\u003e: \u003cerr.Error()\u003e\n```\n\nFor a **primary rate limit** (`RateLimitError`), the agent sees:\n\n```\nsearch code: GET https://api.github.com/search/code: 403 API rate limit exceeded for user ID 12345. [rate reset in 47s]\n```\n\nThe reset time is present but buried inside a raw HTTP method + URL + status string.\n\nFor a **secondary (abuse) rate limit** (`AbuseRateLimitError`), the agent sees:\n\n```\nsearch 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.\n```\n\nThe `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).\n\n### Suggested fix\n\nIn `NewGitHubAPIErrorResponse`, use `errors.As` to detect rate limit error types and return a clean, agent-friendly message:\n\n```go\nfunc NewGitHubAPIErrorResponse(ctx context.Context, message string, resp *github.Response, err error) *mcp.CallToolResult {\n apiErr := newGitHubAPIError(message, resp, err)\n if ctx != nil {\n _, _ = addGitHubAPIErrorToContext(ctx, apiErr)\n }\n\n var rateLimitErr *github.RateLimitError\n if errors.As(err, \u0026rateLimitErr) {\n retryIn := time.Until(rateLimitErr.Rate.Reset.Time).Round(time.Second)\n return utils.NewToolResultError(fmt.Sprintf(\n \"%s: GitHub API rate limit exceeded. Retry after %v.\",\n message, retryIn))\n }\n\n var abuseErr *github.AbuseRateLimitError\n if errors.As(err, \u0026abuseErr) {\n if abuseErr.RetryAfter != nil {\n return utils.NewToolResultError(fmt.Sprintf(\n \"%s: GitHub secondary rate limit exceeded. Retry after %v.\",\n message, abuseErr.RetryAfter.Round(time.Second)))\n }\n return utils.NewToolResultError(fmt.Sprintf(\n \"%s: GitHub secondary rate limit exceeded. Wait before retrying.\",\n message))\n }\n\n return utils.NewToolResultErrorFromErr(message, err)\n}\n```\n\nThis gives the agent clear, actionable output:\n\n```\nsearch code: GitHub API rate limit exceeded. Retry after 47s.\n```\n\n```\nsearch code: GitHub secondary rate limit exceeded. Retry after 60s.\n```\n\n\u003e **Note:** This fix is independent of google/go-github#4180 — it reads `RetryAfter` directly from the struct rather than relying on `.Error()`. The go-github fix benefits all other callers of the library.\n\n\u003e [!NOTE]\n\u003e This issue was drafted with the assistance of GitHub Copilot.\n","author":{"url":"https://github.com/danmoseley","@type":"Person","name":"danmoseley"},"datePublished":"2026-04-25T18:54:58.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":0},"url":"https://github.com/2385/github-mcp-server/issues/2385"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:91f676e5-8c5d-add2-16c0-7bd82b53a974 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | E96E:10F607:F8935F:16768CD:6A622B3D |
| html-safe-nonce | bb51ac8c06aeec46860e4944f830f6d029f418aa3415b264dc50ed86f9a31600 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJFOTZFOjEwRjYwNzpGODkzNUY6MTY3NjhDRDo2QTYyMkIzRCIsInZpc2l0b3JfaWQiOiI3NjEyNzc5OTcwMDIyMjIyNjUzIiwicmVnaW9uX2VkZ2UiOiJpYWQiLCJyZWdpb25fcmVuZGVyIjoiaWFkIn0= |
| visitor-hmac | b7f2d2a829d4a2580b358188d05b1156965ed4429fdfd9e3d32ada41b97a685b |
| hovercard-subject-tag | issue:4328961598 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/github/github-mcp-server/2385/issue_layout |
| twitter:image | https://opengraph.githubassets.com/0a6d86a276dd5c408137fdb087c3c53328821cb0650a6a020dfbad8f8a30336d/github/github-mcp-server/issues/2385 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/0a6d86a276dd5c408137fdb087c3c53328821cb0650a6a020dfbad8f8a30336d/github/github-mcp-server/issues/2385 |
| og:image:alt | 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 str... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | danmoseley |
| hostname | github.com |
| expected-hostname | github.com |
| None | 0e882415c7b47986d65f899389c870b31642bb1c6f36516eb042618596c60e62 |
| turbo-cache-control | no-preview |
| go-import | github.com/github/github-mcp-server git https://github.com/github/github-mcp-server.git |
| octolytics-dimension-user_id | 9919 |
| octolytics-dimension-user_login | github |
| octolytics-dimension-repository_id | 942771284 |
| octolytics-dimension-repository_nwo | github/github-mcp-server |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 942771284 |
| octolytics-dimension-repository_network_root_nwo | github/github-mcp-server |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 230e2af5fc0870303dd4569d72d2bb393ed52c52 |
| ui-target | canary-2 |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width