Kubernetes Error Guide: 'ImagePullBackOff' / 'ErrImagePull' Image Pull Failures
Fix ImagePullBackOff and ErrImagePull in Kubernetes: diagnose bad image names, missing tags, private registry secrets, expired credentials, rate limits, and DNS.
- #kubernetes
- #troubleshooting
- #errors
- #registry
Overview
ErrImagePull and ImagePullBackOff are the states Kubernetes reports when the kubelet cannot pull a container image onto a node. The kubelet asks the container runtime to fetch the image, the pull fails (bad name, auth error, network error, rate limit), and the pod stays at 0/1 with no container ever starting. ErrImagePull is the immediate failure; after a few retries the kubelet backs off and the status becomes ImagePullBackOff (10s, 20s, 40s, up to 5 minutes between attempts).
You will see this in the pod status:
NAME READY STATUS RESTARTS AGE
web-6d8c9f7b5c-q4n2t 0/1 ImagePullBackOff 0 1m38s
And the underlying reason in the pod’s events:
Failed to pull image "registry.example.com/web:v2.3.1": rpc error: code = NotFound desc = failed to pull and unpack image: failed to resolve reference: not found
It occurs whenever a pod is scheduled and the image is not already cached on the node — at first deploy, on a new node, after an image tag change, or after registry credentials expire. The pull is node-and-registry specific, so an image that pulls on one node can fail on another with different DNS, credentials, or cached layers.
Symptoms
- Pod stays
0/1withSTATUSofErrImagePullthenImagePullBackOff. RESTARTSstays0— the container never starts, so there is nothing to restart.kubectl describe podshows aFailed/Failed to pull imageevent with the registry’s error.- No container logs exist yet (
kubectl logsreturns an error).
kubectl get pods -l app=web
NAME READY STATUS RESTARTS AGE
web-6d8c9f7b5c-q4n2t 0/1 ImagePullBackOff 0 1m38s
kubectl describe pod web-6d8c9f7b5c-q4n2t | grep -A8 Events
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 1m38s default Successfully assigned prod/web-6d8c9f7b5c-q4n2t to node-2
Normal Pulling 1m37s kubelet Pulling image "registry.example.com/web:v2.3.1"
Warning Failed 1m35s kubelet Failed to pull image "registry.example.com/web:v2.3.1": not found
Warning Failed 1m35s kubelet Error: ErrImagePull
Normal BackOff 24s (x4 over 1m34s) kubelet Back-off pulling image "registry.example.com/web:v2.3.1"
Warning Failed 24s (x4 over 1m34s) kubelet Error: ImagePullBackOff
Common Root Causes
1. Typo in the image name or tag
A misspelled repository or image name resolves to a reference that does not exist, and the registry returns a not-found error.
kubectl get pod web-6d8c9f7b5c-q4n2t -o jsonpath='{.spec.containers[0].image}'
kubectl describe pod web-6d8c9f7b5c-q4n2t | grep -i 'Failed to pull'
registry.example.com/web-api:v2.3.1
Failed to pull image "registry.example.com/web-api:v2.3.1": failed to resolve reference: not found
The repository is actually web (not web-api). Correct the image string in the Deployment and the pull succeeds.
2. The tag does not exist
The repository is right but the tag was never pushed, or a CI job referenced a tag before it was published. The manifest for that tag is missing.
kubectl describe pod web-6d8c9f7b5c-q4n2t | grep -i 'manifest\|not found'
Failed to pull image "registry.example.com/web:v2.3.1": manifest unknown: manifest unknown
manifest unknown means the repo exists but v2.3.1 does not. Verify the tag with crane ls registry.example.com/web or your registry UI and push or re-tag it.
3. Private registry with no imagePullSecret
Pulling a private image without a registry secret returns an authorization-required error because the request is anonymous.
kubectl describe pod web-6d8c9f7b5c-q4n2t | grep -i 'auth\|unauthorized\|denied'
kubectl get pod web-6d8c9f7b5c-q4n2t -o jsonpath='{.spec.imagePullSecrets}'
Failed to pull image "registry.example.com/web:v2.3.1": failed to authorize: 401 Unauthorized
[]
The empty imagePullSecrets confirms no credentials are attached. Create a docker-registry secret and reference it (see Diagnostic Workflow Step 4).
4. Expired or invalid registry credentials
An imagePullSecret exists but its token/password has expired or is wrong, so the registry rejects the authenticated pull.
kubectl get secret regcred -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d
kubectl describe pod web-6d8c9f7b5c-q4n2t | grep -i 'denied\|forbidden'
{"auths":{"registry.example.com":{"username":"ci","auth":"Y2k6b2xkdG9rZW4="}}}
Failed to pull image "registry.example.com/web:v2.3.1": failed to authorize: 403 Forbidden: access denied
The credentials decode to a stale token. Recreate the secret with a current credential and re-deploy.
5. Registry rate limiting (Docker Hub)
Anonymous or free-tier pulls from Docker Hub are rate-limited; once a node hits the limit, pulls fail with a toomanyrequests error until the window resets.
kubectl describe pod web-6d8c9f7b5c-q4n2t | grep -i 'toomanyrequests\|rate limit'
Failed to pull image "nginx:1.27": toomanyrequests: You have reached your pull rate limit. You may increase the limit by authenticating and upgrading: https://www.docker.com/increase-rate-limit
Authenticate the pulls with an imagePullSecret for Docker Hub, or mirror the image into a private registry to remove the dependency on Hub’s limits.
6. Wrong/unreachable registry or air-gapped node
A node that cannot reach the registry — wrong hostname, firewall, or an air-gapped cluster expected to use a local mirror — fails the pull with a connection or TLS error.
kubectl describe pod web-6d8c9f7b5c-q4n2t | grep -i 'dial\|tls\|connection\|no such host'
Failed to pull image "registry.example.com/web:v2.3.1": dial tcp 203.0.113.10:443: connect: connection timed out
The node has no route to the registry (firewall or air-gap). Point the pod at the in-cluster mirror, or fix the network/firewall path to the registry.
7. Node cannot resolve registry DNS
If the node’s DNS cannot resolve the registry hostname, the pull fails before any TCP connection — distinct from a reachable-but-rejecting registry.
kubectl describe pod web-6d8c9f7b5c-q4n2t | grep -i 'no such host\|server misbehaving'
kubectl get events --field-selector reason=Failed -n prod | tail -3
Failed to pull image "registry.internal/web:v2.3.1": dial tcp: lookup registry.internal on 10.96.0.10:53: no such host
no such host means name resolution failed. Check the registry hostname, the node’s resolver, and any /etc/hosts or split-horizon DNS the cluster relies on.
Diagnostic Workflow
Step 1: Confirm the status and the exact image
kubectl get pods -l app=<APP> -o wide
kubectl get pod <POD> -o jsonpath='{.spec.containers[0].image}'
ErrImagePull/ImagePullBackOff with RESTARTS = 0 confirms a pull failure, not a crash. Note the full image string and the node.
Step 2: Read the pull error from events
kubectl describe pod <POD> | grep -A10 Events
kubectl get events --field-selector involvedObject.name=<POD> --sort-by='.lastTimestamp'
The Failed to pull image message classifies the cause: not found/manifest unknown (name/tag), 401/403 (auth), toomanyrequests (rate limit), dial tcp/no such host (network/DNS).
Step 3: Verify the image name and tag exist
crane ls registry.example.com/web 2>/dev/null
crane manifest registry.example.com/web:v2.3.1 >/dev/null && echo OK || echo MISSING
Confirm both the repository and the specific tag are present in the registry before assuming an auth or network problem.
Step 4: Check or create the imagePullSecret
kubectl get pod <POD> -o jsonpath='{.spec.imagePullSecrets}'
kubectl create secret docker-registry regcred \
--docker-server=registry.example.com \
--docker-username=<USER> --docker-password=<TOKEN> \
-n <NS>
kubectl patch serviceaccount default -n <NS> \
-p '{"imagePullSecrets":[{"name":"regcred"}]}'
Attach the secret to the pod (via the Deployment) or to the ServiceAccount so every pod inherits it.
Step 5: Test connectivity and DNS from a node
kubectl get events --field-selector reason=Failed -n <NS> | tail -5
# from a debug pod on the affected node:
kubectl debug node/<NODE> -it --image=busybox -- nslookup registry.example.com
kubectl debug node/<NODE> -it --image=busybox -- wget -qO- https://registry.example.com/v2/
A failed nslookup is DNS; a failed wget/timeout with successful resolution is routing/firewall.
Example Root Cause Analysis
A new service payments-worker is deployed and stays at 0/1.
kubectl get pods -l app=payments-worker
NAME READY STATUS RESTARTS AGE
payments-worker-7b9c4d6f8-mn5kp 0/1 ImagePullBackOff 0 2m05s
The events show an auth failure, not a missing image:
kubectl describe pod payments-worker-7b9c4d6f8-mn5kp | grep -i 'Failed to pull'
Failed to pull image "registry.example.com/payments:v1.4.0": failed to authorize: 401 Unauthorized
So we check whether any pull secret is attached:
kubectl get pod payments-worker-7b9c4d6f8-mn5kp -o jsonpath='{.spec.imagePullSecrets}'
[]
The image is private, but the new Deployment was created without referencing the registry secret that other workloads use. The pull is anonymous, so the registry returns 401.
Fix: attach the existing regcred secret to the ServiceAccount and restart the rollout:
kubectl patch serviceaccount default -n prod \
-p '{"imagePullSecrets":[{"name":"regcred"}]}'
kubectl rollout restart deployment payments-worker
The next pull authenticates, the image lands, and the pod reaches 1/1 Running.
Prevention Best Practices
- Pin images by immutable digest (
@sha256:...) or at least an explicit tag, neverlatest, so the referenced image cannot disappear or change underneath a deploy. - Attach
imagePullSecretsto the namespace’s ServiceAccount, not just individual pods, so every workload inherits valid credentials. - Mirror critical public images (Docker Hub base images) into your own registry to avoid rate limits and outages on third-party registries.
- Rotate registry credentials with automation and alert before expiry; an expired token turns every new pod into an
ImagePullBackOff. - Validate that new nodes can resolve and reach the registry as part of node bootstrap, especially in air-gapped clusters that depend on a local mirror.
- Verify the tag exists in the registry in CI before the deploy references it. See more in Kubernetes & Helm guides.
Quick Command Reference
# See the pull failure and the exact image
kubectl get pods -l app=<APP> -o wide
kubectl get pod <POD> -o jsonpath='{.spec.containers[0].image}'
# Why did the pull fail?
kubectl describe pod <POD> | grep -A10 Events
kubectl get events --field-selector involvedObject.name=<POD> --sort-by='.lastTimestamp'
# Verify the image/tag exists in the registry
crane ls registry.example.com/<repo>
crane manifest registry.example.com/<repo>:<tag>
# Inspect / create the pull secret
kubectl get pod <POD> -o jsonpath='{.spec.imagePullSecrets}'
kubectl create secret docker-registry regcred \
--docker-server=<REGISTRY> --docker-username=<USER> --docker-password=<TOKEN> -n <NS>
kubectl patch serviceaccount default -n <NS> \
-p '{"imagePullSecrets":[{"name":"regcred"}]}'
# Test DNS/connectivity from the affected node
kubectl debug node/<NODE> -it --image=busybox -- nslookup <REGISTRY>
# Restart the workload after a fix
kubectl rollout restart deployment <DEPLOY>
Conclusion
ErrImagePull and ImagePullBackOff mean the kubelet could not fetch the container image onto the node. The usual root causes:
- A typo in the image repository or name that resolves to nothing.
- A tag that was never pushed to the registry (
manifest unknown). - A private image with no
imagePullSecretattached, so the pull is anonymous. - Expired or invalid registry credentials returning
403/denied. - Registry rate limiting (Docker Hub
toomanyrequests). - A wrong, firewalled, or air-gapped registry the node cannot reach.
- A node that cannot resolve the registry’s DNS (
no such host).
Read the Failed to pull image event first — its wording (not found, 401, toomanyrequests, no such host) points straight at the category before you touch credentials or networking.
Download the Free 500-Prompt DevOps AI Toolkit
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.