Docker Error Guide: 'unexpected EOF' on Image Pull — Fix Broken Layer Downloads
Fix Docker 'unexpected EOF' during pull: repair truncated layer downloads from network drops, proxy/MTU issues, registry timeouts, and corrupt cache, then pull large images reliably.
- #docker
- #troubleshooting
- #errors
- #registry
Fixing errors like this? Get 500 free DevOps AI prompts
500 copy-paste AI prompts for the stack you actually run — one PDF, free.
Overview
unexpected EOF during docker pull means the connection carrying a layer closed before Docker received all the bytes it expected. The download stream ended mid-transfer, so the layer cannot be verified or extracted. It is almost always a transport problem — a dropped connection, a proxy cutting the stream, an MTU mismatch, or a registry timeout — rather than a bad image.
The literal error appears while pulling or extracting a layer:
docker pull myregistry.example.com/app:latest
...
a1b2c3d4e5f6: Downloading [==============> ] 312.4MB/512MB
failed to register layer: unexpected EOF
A close variant surfaces from the daemon as:
Error response from daemon: unexpected EOF
Symptoms
- Pulls of large images fail partway, often at the same approximate percentage each time.
- Small images pull fine; only big layers fail — a classic sign of an MTU or timeout ceiling.
- Retrying sometimes succeeds, sometimes fails at a different point (flaky network/proxy).
- The failure follows a corporate proxy, VPN, or firewall in the path.
journalctl -u dockershows repeatedunexpected EOFornet/http: request canceled.
Common Root Causes
- Network instability — Wi-Fi drops, VPN flaps, or a saturated link interrupting a long-running layer download.
- Proxy or firewall cutting the stream — an inspecting proxy that buffers or times out large responses and closes the connection early.
- MTU mismatch — an oversized MTU (common with VPN/overlay networks) blackholes large packets, so big layers stall and the connection dies.
- Registry-side timeout or rate limiting — the registry closes idle or slow connections, or throttles the client mid-transfer.
- Corrupt local download cache — a partially written layer in
/var/lib/dockerthat the daemon keeps trying to reuse. - Insufficient concurrency limits under load — many parallel layer pulls overwhelming a constrained link.
Diagnostic Workflow
Confirm it is transport, not the image, by retrying and watching where it breaks:
docker pull --disable-content-trust myregistry.example.com/app:latest
journalctl -u docker --since '5 min ago' | grep -i 'eof\|canceled\|timeout\|tls'
Test raw connectivity and payload transfer to the registry, bypassing Docker:
curl -v -o /dev/null https://registry-1.docker.io/v2/
time curl -sS -o /dev/null https://<registry>/v2/<repo>/blobs/<digest>
Check for an MTU problem — large packets failing while small ones pass:
ping -M do -s 1472 registry-1.docker.io # 1472+28=1500; try 1400 if this fails
ip link show docker0 | grep mtu
Inspect proxy configuration the daemon is using:
systemctl show --property=Environment docker | tr ' ' '\n' | grep -i proxy
cat /etc/systemd/system/docker.service.d/http-proxy.conf 2>/dev/null
Example Root Cause Analysis
A CI runner behind a corporate VPN failed to pull a 1.8 GB ML image, dying near 60% every time with failed to register layer: unexpected EOF. Small images pulled fine. ping -M do -s 1472 failed but -s 1372 succeeded — a classic MTU blackhole introduced by the VPN tunnel, which had an effective MTU below 1500.
The fix was to lower Docker’s MTU to match the tunnel by setting "mtu": 1400 in /etc/docker/daemon.json and restarting the daemon. With packets sized to fit the path, the large layers transferred intact and the pull completed. As a belt-and-suspenders measure, the team also added a pull retry with backoff in the pipeline to absorb transient VPN flaps.
Prevention Best Practices
- Match MTU to the path. On VPN/overlay/cloud networks, set Docker’s
mtuindaemon.jsonto the tunnel’s real MTU to avoid large-packet blackholes. - Retry pulls with backoff in CI so a single transient EOF does not fail the whole job.
- Use a pull-through registry mirror close to your builders to shorten and stabilize the download path.
- Exempt registries from stream-inspecting proxies, or ensure the proxy supports large, long-lived responses.
- Prune corrupt partial layers if a specific pull keeps failing at the same point (
docker system prunethen re-pull). - Keep images lean so individual layers are smaller and less likely to be interrupted.
Quick Command Reference
docker pull <image> # reproduce
journalctl -u docker | grep -i eof # daemon-side detail
ping -M do -s 1472 <registry-host> # MTU probe (drop to 1400)
ip link show docker0 | grep mtu # current bridge MTU
curl -v -o /dev/null https://<registry>/v2/ # raw reachability
docker system prune # clear corrupt partials
# /etc/docker/daemon.json -> { "mtu": 1400 } then: systemctl restart docker
Conclusion
unexpected EOF on pull is a broken download, not a broken image: the byte stream ended early. Prove it is transport by testing raw connectivity and probing MTU, then fix the path — right-size MTU for VPN/overlay networks, exempt the registry from stream-cutting proxies, and add pull retries. A nearby registry mirror makes large pulls dramatically more reliable. See also the net/http request canceled guide and the full Docker guides.
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.