Docker "toomanyrequests: rate limit exceeded" - Fix Docker Hub Pull Limits
Docker Hub enforces anonymous pull-rate limits per IP. On shared CI infrastructure you share that IP with everyone else on the runner pool, so unauthenticated pulls hit the limit quickly.
What this error means
An image pull fails with a 429 Too Many Requests from Docker Hub. It is intermittent by nature - the same workflow passes minutes later once the limit window resets.
Error response from daemon: 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 an IP-based quota
Hosted CI runners pull from a shared NAT IP. Docker Hub counts pulls per IP for anonymous users, so your job is rate-limited by everyone else’s pulls too.
No authentication
Authenticated pulls get a much higher quota tied to your account rather than the shared runner IP.
How to fix it
Authenticate to Docker Hub
Log in with an access token before pulling. This moves you off the anonymous shared-IP quota.
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}Cache or mirror base images
- Pull base images through a registry mirror or your cloud provider’s registry cache.
- Mirror frequently-used base images into your own registry (GHCR, ECR, Artifact Registry) and pull from there.
- Cache built images between runs so you do not re-pull bases on every job.
Add a bounded retry
Because the limit is a transient, time-windowed condition, a short backoff retry often succeeds without any other change.
How to prevent it
- Always authenticate to Docker Hub in CI, even for public images.
- Pull base images from a registry you control or a pull-through cache.
- Pin base image digests so cached layers are reused.