Docker "ERROR: load metadata" rate limit in CI
BuildKit resolves the base image manifest before building. When anonymous Docker Hub pulls exceed the hourly cap, that metadata lookup fails with a rate-limit response and the build never starts.
What this error means
A build fails at the FROM resolution with ERROR: failed to load metadata for docker.io/library/<image> and a 429 Too Many Requests / toomanyrequests underneath. Retrying later or while authenticated succeeds.
ERROR: failed to solve: failed to load metadata for docker.io/library/node:20:
failed to authorize: failed to fetch oauth token: unexpected status from GET request: 429 Too Many RequestsCommon causes
Anonymous pulls exceeded the hourly limit
Docker Hub limits unauthenticated pulls per IP. Shared CI egress IPs hit the cap quickly.
No registry authentication in CI
The job pulls anonymously, getting the lowest rate-limit tier.
How to fix it
Authenticate to Docker Hub
- Log in before building to raise the limit and stabilize pulls.
- uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USER }}
password: ${{ secrets.DOCKERHUB_TOKEN }}Avoid Docker Hub for base images
- Mirror base images to GHCR or ECR and pull from there.
- Cache base layers between runs.
How to prevent it
- Authenticate to the registry and mirror base images off Docker Hub. Because rate limits are transient and time-windowed, self-healing managed runners such as Latchkey auto-retry them after a short backoff, so a momentary 429 does not fail the build.