Skip to content
Hack Your WorldSoftware · Infrastructure · Home automation

Analysis

GitLab’s New Rate Limits Won’t Break Git. They’ll Expose Bad Automation.

Automated requests queuing at a shared rate-limit gate
AI image: Hack Your World

GitLab.com is changing its rate limits on October 19. The ordinary work most people associate with GitLab—pushing code, reviewing a merge request, or running a normal pipeline—is unlikely to notice. The forgotten dashboard refreshing every few seconds is another matter.

So is the agent that turns one user request into a project search, three issue lookups, a merge-request query, and several follow-up calls before anyone realizes it has spent part of a shared hourly budget.

GitLab says Free accounts and unauthenticated traffic move to the new limits on October 19, 2026. Premium and Ultimate follow in January 2027. Before the first change, GitLab will enable the limits during two four-hour brownouts on October 7 and October 14, both beginning at 15:00 UTC.

The important number for anonymous traffic is 60 requests per hour per IP address. That applies even when an unauthenticated script is reading a public project owned by a paying customer. Authentication moves a request to the plan allowance: 5,000 requests per hour for Free, 15,000 for Premium, and 25,000 for Ultimate. There are also per-minute burst ceilings.

This is not really a Git story. It is an inventory test for everything adjacent to Git.

The first failure will probably be something nobody owns

GitLab’s advice starts with authentication, and it should. Sixty requests per hour is one request a minute. A status panel that polls every 30 seconds can consume twice that by itself. Put several anonymous jobs behind one office NAT address and they share the same IP allowance.

The likely offenders are not dramatic: a shell script copied into cron years ago, a browser extension, a public status badge, an internal dashboard, or a monitoring check that nobody thought of as an API client. These are exactly the things that keep working until an external limit changes.

Authentication is not the complete fix. The new allowance is also a budget, not permission to ignore request volume. GitLab says the limits are applied per user and per top-level group. Its currently published plan table gives the user figures but does not yet spell out a separate group table. I would monitor the documentation rather than designing around an assumed group number.

A shared personal access token is especially easy to misunderstand. Ten services using one token do not have ten independent allowances. They appear as one user. The busiest integration can leave every other integration looking broken.

That argues for service identities where the account model permits them, and at minimum for knowing which jobs share credentials. Creating more tokens for the same user does not create more users.

“We retry 429s” is not the same as being quota-aware

I maintain a GitLab MCP server, so this change is not abstract for me. I reviewed its outbound request path against the new policy.

The client already routes GraphQL and REST traffic through a common concurrency gate. It caps pagination, treats HTTP 429 as retryable, reads Retry-After, and uses exponential backoff with jitter for other transient failures. Those are sensible protections. They still do not make the service fully quota-aware.

Concurrency and quota are different controls. A limit of 16 simultaneous requests can prevent a burst from turning into hundreds of in-flight calls. It cannot stop a steady stream from using 5,000 requests over an hour. A retry that correctly waits for Retry-After also preserves work; it does not reduce the amount of work waiting behind it.

There is a nastier failure mode when several workers share a credential. They hit the ceiling together, sleep for the same reset, and wake together. Jitter helps, but the better design is a shared view of the budget: capture RateLimit-Remaining, slow producers before zero, and coordinate retries at the credential or group boundary rather than inside each process.

GitLab notes that some Projects, Groups, and Users API responses do not include the informational headers. Other endpoint-specific limits can also return a 429 even when an earlier response showed capacity remaining. Telemetry should therefore treat the headers as useful signals, not a complete model of every limiter in front of the request.

Agents make inefficient clients much easier to build

An MCP tool or coding agent changes the unit people see. The user asks one question; the system may make many API calls.

A request such as “what changed in this group today?” can require project discovery, pagination across activity, user resolution, issue details, merge-request details, and perhaps comments or pipelines. If the first search is too broad, the model may refine it and make more calls. None of that is inherently wrong, but the human-visible request count no longer resembles the GitLab request count.

This is where tool design matters. A useful agent integration should:

  • authenticate every request;
  • bound fan-out and total items, not only page size;
  • prefer one well-shaped query over a chain of tiny lookups;
  • cache stable metadata such as user and project resolution;
  • expose truncation instead of silently chasing every page;
  • limit concurrency across the entire service, not separately inside every tool;
  • log request cost by user, token role, tool, and top-level group;
  • honor Retry-After and avoid automatic retries for unsafe writes;
  • make a broad “fetch all” operation an explicit choice.

The last point is easy to miss. Pagination is good because it prevents giant responses. Automatically walking every page can still be expensive. A bounded result that says more data exists is often more useful than an exhaustive result that consumes the budget and overwhelms the model with context.

Use the brownouts as a production test

GitLab is giving operators two useful test windows. I would treat them like a planned dependency exercise, not wait to see whether someone files a ticket on October 19.

Start by searching code and configuration for gitlab.com, /api/v4, /api/graphql, old private tokens, and anonymous curl calls. Inventory scheduled jobs, monitoring systems, bots, IDE extensions, MCP servers, CI helpers, and anything running behind shared egress.

During each brownout, record 429s, Retry-After, RateLimit-Remaining, queue depth, request latency, and the credential responsible. Watch for a service that remains technically healthy while its queue grows faster than it drains. That is a delayed outage.

Then decide what the workload actually needs. Add authentication where it was omitted. Replace polling with webhooks or events when the use case allows it. Cache responses that do not need to be live. Put an upper bound on fan-out. Give important workloads separate identities instead of one mystery token. If the application legitimately needs more capacity, GitLab says purchasable headroom is being designed, but it has not published the offer yet.

The change does not affect GitLab Self-Managed or GitLab Dedicated; those remain under the operator’s limits. It also does not mean normal GitLab.com use suddenly becomes fragile. GitLab says almost all users already fall inside the new ceilings.

That is believable. Most people are not the problem. Unobserved automation is.

Rate limits have a habit of revealing architecture that was always there: shared identities, accidental polling, unlimited traversal, synchronized retries, and systems with no owner. GitLab’s October change gives those systems a date on the calendar.

Sources