Stale GET /rate_limit GH API calls returning a frozen "fresh" window answer instead of real usage at some circumstances
#207319
Unanswered
rastislav-bostik-tb
asked this question in
Apps, API and Webhooks
Replies: 1 comment
|
💬 Your Product Feedback Has Been Submitted 🎉 Thank you for taking the time to share your insights with us! Your feedback is invaluable as we build a better GitHub experience for all our users. Here's what you can expect moving forward ⏩
Where to look to see what's shipping 👀
What you can do in the meantime 💻
As a member of the GitHub community, your participation is essential. While we can't promise that every suggestion will be implemented, we want to emphasize that your feedback is instrumental in guiding our decisions and priorities. Thank you once again for your contribution to making GitHub even better! We're grateful for your ongoing support and collaboration in shaping the future of our platform. ⭐ |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
🏷️ Discussion Type
Bug
💬 Feature/Topic Area
API
Body
What
It seems that
GET /rate_limitGH API endpoint, at some circumstances, becomes returning a frozen "fresh" window answer instead of real usage.What I'm seeing: some rate-limit keys:
GET /rate_limitstops reflecting real usage —used: 0,resetpinned tonow+3600s(+60sforsearch), every call, regardless of real spend. Ruled out client/edge caching, aghCLI bug, different identity (below). Not the documented "stale replica" mode either — that gives an old nonzero value, not a perpetual fresh one. Could be missing something — happy to be corrected.Reproduction
Two calls, same token, same second:
Same
coreresource, same instant, same token: one path shows 48 used with a live window, the other 0 used with a window pinned exactly 3600s from whenever you ask.Ruled out
gh/curleach time, no local HTTP cache./rate_limitcarriesCache-Control: no-cache. Two back-to-back calls in the same second return differentX-Github-Request-Id— genuinely fresh backend hits, not replays.X-Oauth-Client-Ididentical.ghCLI bug: reproduces ongh2.87.3 and 2.100.0, and with plaincurl(nogh) through 4+api.github.comfront-end IPs.gho_...) and, per evidence below, a repository's ownGITHUB_TOKEN.Proof set — two other orgs, same ~48h onset window
Identical signature (
used: 0,reset=now+3600s) in public Actions job logs of two unrelated repos, starting the same 2-day window:tenstorrent/tt-metal, workflow
_produce-data.yaml, jobproduce-cicd-data, authenticating with${{ github.token }}(i.e.GITHUB_TOKEN):used=4814(2026-08-27 12:00 UTC)used=4337(2026-08-28 00:00 UTC)used=0, reset=+3600s(2026-08-28 23:59 UTC)used=0, reset=+3600s(2026-09-07 15:14 UTC)cashapp/hermit-packages, workflow
autoversion.yml, using a separate PAT-style secret (notGITHUB_TOKEN):used=326(2026-08-27 17:48 UTC)used=0(2026-08-28 05:20 UTC)used=0(2026-09-07 02:43 UTC)Both broke independently within the same ~48h window (2026-08-27 evening – 2026-08-28 night UTC), on two unrelated orgs' tokens — one
GITHUB_TOKEN, one PAT-style.Not universal: a third repo, centreon/centreon (
check-status.yml, alsoGITHUB_TOKEN), shows a healthy, correctly-decrementing counter as of today — not every key, not everyGITHUB_TOKEN. Looks key/shard-dependent, not token-type.A guess at the mechanism (could easily be wrong)
Your own engineering blog ("How we scaled the GitHub API with a sharded, replicated rate limiter in Redis") describes keys sharded across Redis: one primary (writes) + read replicas per cluster;
GET /rate_limitreads a replica, real headers reflect the write path. Same post documents a related past failure — a stale replica returning an oldusedvalue with a newreset. If that's still how it works, this looks like the read path finding no window at all and synthesizing a fresh one — different (and worse) than the documented failure. Guess from the outside, not confirmed.Is this worth a look?
/rate_limitis the endpoint your docs recommend when you can't rely on response headers (gated jobs, dashboards). A subset of keys silently, durably reporting "fully fresh, nothing used" for 10+ days seemed worth flagging even if I've got part of this wrong.Didn't dig much deeper than this — just reporting an observed behavior that looked wrong, not a deep investigation. Am I missing something?
Can't offer a strict MRE — seems per-key/per-shard, not reproducible on demand for any token, only whichever ones are affected. If you can reproduce it reliably (or can't at all), that itself tells me something.
All reactions