Troubleshooting guide · ImagePullBackOff

ImagePullBackOff and ErrImagePull: why Kubernetes cannot pull the image

ErrImagePull means the node tried to pull a container image and failed; ImagePullBackOff is the kubelet waiting before it tries again. The pod's events carry the registry's own answer — not found, unauthorised, too many requests — and that answer decides the fix.

Updated

Read the registry's answer

The status only says the pull failed. The event says why, in the words the registry or the container runtime used:

The Events at the bottom carry lines like Failed to pull image followed by the reason:

kubectl describe pod <pod> -n <namespace>

The exact image reference the pod asked for:

kubectl get pod <pod> -n <namespace> -o jsonpath='{.spec.containers[*].image}'

What the message means

  • not found, or manifest unknown: the repository or the tag does not exist. Check the spelling, the registry host, and that the tag was actually pushed.
  • unauthorized, or pull access denied: the registry wants credentials and the pod did not present valid ones. See the next section.
  • toomanyrequests, or 429: the registry is rate-limiting pulls. Docker Hub limits pulls per account and, more tightly, per anonymous address — authenticate, or pull through a mirror.
  • no match for platform in manifest: the image was not built for the node's CPU architecture, such as an amd64-only image on an arm64 node.
  • timeouts, connection refused, or no such host: the node cannot reach the registry. Check DNS, proxies and egress rules from the node, not from your laptop.

Private registries: imagePullSecrets

A pod authenticates to a registry with a Secret of type kubernetes.io/dockerconfigjson, named in its imagePullSecrets or in its service account's. The Secret must be in the same namespace as the pod.

Which pull secrets the pod uses:

kubectl get pod <pod> -n <namespace> -o jsonpath='{.spec.imagePullSecrets}'

Create one from a Docker config file that already holds the login, which keeps the password out of your shell history. If your Docker config keeps logins in a credential helper, the file holds no password; use kubectl create secret docker-registry instead:

kubectl create secret generic regcred -n <namespace> --type=kubernetes.io/dockerconfigjson --from-file=.dockerconfigjson=$HOME/.docker/config.json

Let every pod using the namespace's default service account present it:

kubectl patch serviceaccount default -n <namespace> -p '{"imagePullSecrets": [{"name": "regcred"}]}'

Retry the pull

After a fix the kubelet retries on its own, but the back-off can be several minutes long. Deleting the pod lets its controller create a new one that pulls straight away:

Recreate the pods of a Deployment:

kubectl rollout restart deployment/<name> -n <namespace>

What PodSteer does about it.

  • An image that cannot be pulled is a finding on the overview, grouped by the workload it belongs to.
  • The finding names both causes that look identical in the status — a tag that does not exist, and a node with no credentials for the registry — so neither gets ruled out by assumption.
  • The image pane names the pod's pull secrets without reading them, and shows the digest the kubelet actually resolved.
PodSteer's cluster overview with its findings open under a banner reading Needs attention, 4 critical and 5 warning findings. Listed: an image that cannot be pulled for two pods of storefront/reviews, two unschedulable pods of storefront/search-indexer, CrashLoopBackOff for the image-resizer deployment, an unschedulable Trivy scanner job, and the start of a warning about failing startup probes. Each finding says what the state means. PodSteer's cluster overview with its findings open under a banner reading Needs attention, 4 critical and 5 warning findings. Listed: an image that cannot be pulled for two pods of storefront/reviews, two unschedulable pods of storefront/search-indexer, CrashLoopBackOff for the image-resizer deployment, an unschedulable Trivy scanner job, and the start of a warning about failing startup probes. Each finding says what the state means.
Findings, named by the workload. Each finding names the workload it belongs to and says what the state means, before a single pod has been opened.

CrashLoopBackOff

The container starts, exits and is restarted with a growing delay. Find the reason in the previous attempt's logs and its exit code.

Pod stuck in Pending

No node can take the pod. The scheduler's FailedScheduling event names every constraint that ruled a node out.

OOMKilled

The container used more memory than its limit and the kernel killed it. Confirm it, measure the real peak, then size the limit or fix the leak.