Docker "net/http: request canceled (Client.Timeout exceeded)" on Pull/Push
Docker’s HTTP client gave up waiting for the registry. The connection or response exceeded the client timeout - a transient network, DNS, or proxy slowdown between the runner and the registry.
What this error means
A docker pull/push fails with net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers). It is intermittent - re-running the job often succeeds with no change.
Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http:
request canceled while waiting for connection (Client.Timeout exceeded while
awaiting headers)Diagnose it: separate auth from naming from rate limits
Registry errors look alike and have unrelated causes. Work out which of the three you have before changing credentials, because a malformed image reference produces an error that reads like an authentication failure.
# 1. is the reference even valid? (lowercase, no spaces, valid tag)
docker image inspect "$IMAGE" 2>&1 | head -2
# 2. are you authenticated to the right registry?
cat ~/.docker/config.json | grep -o '"[^"]*\.[^"]*"' | head
# 3. are you rate limited? (Docker Hub anonymous pulls)
curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:ratelimit-preview/test:pull" \
| grep -o '"token"' >/dev/null && echo "token ok"Common causes
Transient network or registry slowness
A brief connectivity blip, an overloaded registry edge, or a congested runner network makes the request exceed Docker’s client timeout. Nothing about your image is wrong.
DNS resolution stalling
Slow or failing DNS for the registry host delays the connection past the timeout, especially on runners with a flaky resolver.
A proxy/firewall silently dropping the connection
An HTTP(S) proxy or firewall that blackholes the registry connection causes the client to wait until it times out.
How to fix it
Retry with backoff
Because the failure is transient, a bounded retry usually succeeds without other changes.
for i in 1 2 3; do
docker pull myorg/api:1.4.2 && break
echo "pull timed out (attempt $i), retrying..."; sleep $((i*10))
doneFix DNS and proxy reachability
- Confirm the registry host resolves (
getent hosts registry-1.docker.io). - Set
HTTP_PROXY/HTTPS_PROXY/NO_PROXYcorrectly for the daemon if a proxy is required. - Use a closer mirror or pull-through cache to reduce round-trip time.
Authenticate in the job, not in the image
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# GHCR needs this on the job or the push is rejected as unauthorised
permissions:
contents: read
packages: writeHow to prevent it
- Wrap pulls/pushes in a bounded retry with backoff.
- Ensure reliable DNS and correct proxy settings on runners.
- Mirror or cache base images to cut dependence on a slow public registry.