Skip to content
Latchkey

Docker Hub "toomanyrequests: You have reached your pull rate limit" in CI

Docker Hub enforces a pull rate limit counted per IP for anonymous and free accounts. CI runners share outbound IPs, so the pool drains fast and Docker Hub returns 429 "toomanyrequests". Authenticating raises the limit and counts pulls against your account instead of the shared IP.

What this error means

A docker pull (often of a base image during build) fails with "toomanyrequests: You have reached your pull rate limit." and a link to docker.com/increase-rate-limit.

docker
toomanyrequests: You have reached your pull rate limit. You may increase the limit
by authenticating and upgrading: https://www.docker.com/increase-rate-limit

Common causes

Anonymous pulls share the runner IP pool

Without login, Docker Hub counts pulls per IP. Many jobs on shared CI egress exhaust the anonymous quota.

No authenticated pull-through or mirror

Every build re-pulls base images from docker.io with no cache or mirror, multiplying requests against the limit.

How to fix it

Authenticate pulls to use the per-account limit

  1. Add a Docker Hub login step before any build that pulls from docker.io.
  2. Pulls now count against your account, which has a higher limit.
  3. Use a paid or org account if your volume needs more headroom.
.github/workflows/ci.yml
- uses: docker/login-action@v3
  with:
    username: ${{ secrets.DOCKERHUB_USERNAME }}
    password: ${{ secrets.DOCKERHUB_TOKEN }}

Pull base images through a mirror or cache

Configure a registry mirror or pull common base images from a private registry copy so docker.io is hit far less often.

daemon.json
# daemon.json on the runner
{ "registry-mirrors": ["https://mirror.gcr.io"] }

How to prevent it

  • Authenticate every docker.io pull in CI.
  • Mirror or cache base images to avoid repeat pulls.
  • Pin base image digests so layers cache and re-pull less.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →