Skip to main content

Kubernetes · troubleshooting

ImagePullBackOff

The kubelet cannot retrieve the container image, and is now backing off between attempts. Almost always the name, the credentials, or the network — in that order of likelihood.

Run this first

step 1 of 3
kubectl describe pods <pod>

Look for The exact text after "Failed to pull image"

The registry's own error is quoted verbatim in Events, and it distinguishes all five causes immediately.

Work out which cause you have

A few questions to narrow the list. Every answer ends in a command that confirms or rules the cause out — this cannot see your cluster, so nothing here is a certainty until you have checked.

Narrow it down

0 answered · nothing is sent anywhere

In kubectl describe pod, what does the error after "Failed to pull image" actually say?

The registry's own wording distinguishes every cause here. Quote it exactly rather than paraphrasing.

Cause space

5 of 5 still possible

  • The image name or tag is wrongCommon
  • Missing or wrong registry credentialsCommon
  • The registry is implied rather than statedOccasional
  • The node cannot reach the registryOccasional
  • Registry rate limitingRare

Nothing ruled out yet. Answer the question above and the branches your answer eliminates will strike through here.

Check it with a tool

Or diagnose it manually

In this order. The first command usually contains the whole answer.

  1. Step 1

    kubectl describe pods <pod>

    The registry's own error is quoted verbatim in Events, and it distinguishes all five causes immediately.

    Look for The exact text after "Failed to pull image"

  2. Step 2

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

    Shows the reference as the cluster sees it, which is not always what the manifest appears to say after templating.

    Look for A missing registry host, a wrong tag, or a typo

  3. Step 3

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

    Confirms whether credentials are attached at all before you go looking at the registry.

    Look for Empty output for a private image, or a Secret absent from this namespace

Every cause, and how to fix it

Ordered by how often each one turns out to be the answer.

The image name or tag is wrong

Common

A typo, a tag that was never pushed, or a tag deleted from the registry. The registry answers correctly — it simply has nothing by that name. "manifest unknown" and "not found" both point here.

Confirm

kubectl describe pod <pod> | grep -A5 Events

"manifest unknown", "manifest for ... not found", or "repository does not exist"

Fix

  • Read the image reference back character by character, including the tag.
  • Confirm the tag actually exists in the registry rather than assuming CI pushed it.
  • Avoid :latest — it makes this failure mode ambiguous and non-reproducible.
docker manifest inspect <image>:<tag>

Run from a machine with registry access. Succeeds if the reference resolves.

Missing or wrong registry credentials

Common

The image is private and the kubelet has no usable credentials for it. The imagePullSecrets field is absent, references a Secret that does not exist in this namespace, or holds credentials that have expired. Pull secrets are namespaced, which is the detail that catches people — a Secret that works in one namespace does nothing in another.

Confirm

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

Empty output for a private image, or a Secret name that kubectl get secret cannot find in this namespace

Fix

  • Create a docker-registry Secret in the same namespace as the pod and reference it from imagePullSecrets.
  • Check the credentials have not expired — many registry tokens are short-lived.
  • For cloud registries, prefer the provider's workload identity over long-lived pull secrets.
kubectl create secret docker-registry regcred --docker-server=<registry> --docker-username=<user> --docker-password=<token> -n <namespace>

The registry is implied rather than stated

Occasional

An image reference with no registry host defaults to Docker Hub. If the image actually lives in a private or cloud registry, the kubelet dutifully asks the wrong place and is told the image does not exist. The error looks like a missing image; the cause is a missing hostname.

Confirm

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

A reference with no registry host, when the image is not on Docker Hub

Fix

  • Fully qualify the reference, including the registry host.
  • Prefer digests over tags where reproducibility matters.

The node cannot reach the registry

Occasional

DNS cannot resolve the registry, a firewall or egress policy blocks it, or a required proxy is not configured on the node. Distinguished from the other causes by its error shape: a timeout or connection failure rather than a clear registry response.

Confirm

kubectl describe pod <pod> | grep -i -E 'timeout|no such host|connection refused|i/o timeout'

A network-level error rather than an authentication or not-found response

Fix

  • Test connectivity from the node itself, not from your laptop — the node's network is what matters.
  • Check egress rules, NAT and any proxy configuration the container runtime needs.
  • If DNS is the issue, confirm the node can resolve the registry hostname.

Registry rate limiting

Rare

Public registries limit anonymous pulls. A busy cluster pulling unauthenticated can exhaust the allowance, and pulls that previously worked start failing — which makes this look like an intermittent network problem.

Confirm

kubectl describe pod <pod> | grep -i -E 'rate limit|toomanyrequests'

"toomanyrequests" or an explicit rate-limit message

Fix

  • Authenticate pulls even for public images, which usually raises the allowance substantially.
  • Mirror or cache images you depend on rather than pulling from upstream on every node.

Understanding it properly

Skip this if you are mid-incident — the working part of the page is above. Worth reading afterwards, because understanding the mechanism is what stops the next one.

What is actually happening

Before a container can run, the kubelet has to fetch its image. Pulling an image means resolving the name to a registry, reaching that registry over the network, authenticating if it is private, and finding the requested tag. ImagePullBackOff means one of those four failed and the kubelet is waiting before retrying.

You will often see ErrImagePull first and ImagePullBackOff a moment later. They are the same problem at different stages: the first is the failed attempt, the second is the wait that follows.

The Kubernetes documentation treats this as a case of a pod stuck Waiting — scheduled onto a node, but unable to start. That framing is useful, because it tells you scheduling already succeeded and the fault lies entirely in image retrieval.

How to tell this is your problem
WhereWhat you see
kubectl get podsSTATUS shows ImagePullBackOff or ErrImagePull, 0 restarts
kubectl describe podEvents with "Failed to pull image" and a registry error
The error text"manifest unknown", "unauthorized", "not found", or a timeout

How to know it is actually fixed

  • kubectl describe pod shows a "Successfully pulled image" event.
  • The pod moves past Waiting into Running.
  • Delete the pod and let it be recreated — a successful pull that only worked because of a cached layer will fail again on a different node.

Stopping it happening again

  • Pin images by digest, or at least by an immutable tag. Never :latest in production.
  • Keep pull secrets in every namespace that needs them, and rotate before expiry.
  • Authenticate even public pulls, so rate limits do not surprise you during an incident.
  • Have CI verify the image is pullable before the manifest referencing it is deployed.

Did this get you to an answer?

No text box on purpose — please do not paste production logs anywhere

Sources

Behaviour described here is drawn from official documentation. Where a figure could not be confirmed on an official page it is attributed in the text rather than stated as canonical.

Related

ImagePullBackOff — causes, diagnosis and fix | DevOps Insights