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.
toomanyrequests: You have reached your pull rate limit. You may increase the limit
by authenticating and upgrading: https://www.docker.com/increase-rate-limitCommon 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
- Add a Docker Hub login step before any build that pulls from docker.io.
- Pulls now count against your account, which has a higher limit.
- Use a paid or org account if your volume needs more headroom.
- 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 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.