What ImagePullBackOff means
The kubelet tried to pull the container image and failed, so it is backing off
and retrying. Per the Kubernetes docs, ImagePullBackOff means "a container
could not start because Kubernetes could not pull a container image (for reasons
such as invalid image name, or pulling from a private registry without
imagePullSecret)", and the BackOff part means Kubernetes "will keep trying to
pull the image, with an increasing back-off delay" up to a compiled-in limit of
300 seconds (5 minutes) (kubernetes.io).
The fix depends entirely on the exact pull error, which is in the pod's events.
Diagnose it first
A failure to pull the image is the most common cause of a pod stuck in Waiting,
and the first step is to read the pod's recent events
(kubernetes.io).
kubectl describe pod <pod> -n <namespace>
# Read the Events section. The message after "failed to pull image" tells you which mechanism:
# manifest unknown / not found -> wrong/non-existent tag or digest (see "Wrong tag")
# pull access denied / unauthorized -> registry auth (see "Auth")
# no match for platform in manifest -> arch mismatch at pull time (see "Arch mismatch")
# too many requests / toomanyrequests -> registry rate limit (see "Rate limit")
# no such host / i/o timeout / x509 -> network, DNS, or TLS to registry (see "Reachability")
# ErrImageNeverPull -> imagePullPolicy: Never, image absent (see "Pull policy")
The docs' three first checks: confirm the image name is correct, confirm the
image was pushed to the registry, and try to pull it manually (e.g.
docker pull <image>) from a machine on the same network
(kubernetes.io).
Mechanisms, each end to end
Wrong tag, digest, or image name
The manifest references a tag or digest the registry does not have — often the build pushed a different tag, or there is a typo in the repository/host.
- Diagnose: event says
manifest unknown,manifest for ... not found, orrepository does not exist. Compare theimage:in the spec against what was actually pushed:kubectl get pod <pod> -n <ns> -o jsonpath='{.spec.containers[*].image}', thendocker pull <that-exact-string>to confirm it resolves. - Fix: correct the tag/digest/host in the manifest and redeploy. Prefer an
immutable digest (
image@sha256:...) for production so a re-pushed tag cannot silently change the image (kubernetes.io).
Auth — missing or expired registry credential
A private image with no imagePullSecret, an expired token, or a secret the pod
does not reference.
- Diagnose: event says
pull access denied,unauthorized, orauthentication required. Confirm whether the pod references a secret:kubectl get pod <pod> -n <ns> -o jsonpath='{.spec.imagePullSecrets}'. - Fix (per pod): create a
kubernetes.io/dockerconfigjsonsecret and reference it (kubernetes.io):
kubectl create secret docker-registry regcred \
--docker-server=<registry-server> \
--docker-username=<name> \
--docker-password=<password> \
--docker-email=<email> \
-n <namespace>
apiVersion: v1
kind: Pod
metadata:
name: private-reg
spec:
containers:
- name: private-reg-container
image: <your-private-image>
imagePullSecrets:
- name: regcred
- Fix (every pod in a namespace): attach the secret to the ServiceAccount instead of each pod, so pods using that account inherit it (kubernetes.io):
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-service-account
imagePullSecrets:
- name: regcred
Secret in the wrong namespace
The secret exists but not where the pod runs, so the reference resolves to nothing and auth fails as if no secret were set.
- Diagnose: same
unauthorizedevent, butkubectl get secret regcred -n <ns>returns "not found" in the pod's namespace even though it exists elsewhere. - Fix: the secret must live in the same namespace as the pod — "The namespace to use is the same namespace where you defined the Pod" (kubernetes.io). Recreate the secret in that namespace.
Arch mismatch at pull time
A single-architecture image (say linux/amd64 only) scheduled onto a node of a
different arch (say arm64) has no matching manifest entry, so the pull fails.
- Diagnose: event says
no match for platform in manifest. Check the node arch (kubectl get nodes -o wide/kubectl describe node <node>→kubernetes.io/arch) against the image's supported platforms (docker buildx imagetools inspect <image>). - Fix: publish a multi-arch image covering the node's architecture, or pin the
workload to nodes matching the image with a
nodeSelectoronkubernetes.io/arch. Note: if the image instead has a wrong-arch binary that does pull, it fails later at container start withexec format error(RunContainerError / CrashLoopBackOff), which is not an ImagePullBackOff (kubernetes.io).
Rate limit
Public registries cap pulls per time window (Docker Hub is the common one), and a busy node hits the cap.
- Diagnose: event says
toomanyrequestsorYou have reached your pull rate limit. - Fix: authenticate the pull (an authenticated Docker Hub account has a higher
limit) by adding an
imagePullSecretas above, or pull through a registry mirror / pull-through cache so identical images are not re-fetched per node.
Reachability — network, DNS, TLS, or proxy
The node cannot reach the registry at all.
- Diagnose: event says
no such host(DNS),i/o timeout/connection refused(network/firewall), orx509: certificate signed by unknown authority(TLS — often a self-signed internal registry or a corporate MITM proxy without the CA trusted on the node). - Fix: confirm egress and DNS from the node to the registry host/port; for TLS,
install the registry/proxy CA on the nodes' container runtime trust store. Retry
the manual
docker pullfrom the node itself to isolate node-vs-cluster.
Pull policy — image absent and Never/IfNotPresent
With imagePullPolicy: Never, the kubelet never fetches; if the image is not
already on the node, startup fails. The status here is usually ErrImageNeverPull
rather than a backoff, but it is the same family of "image not available."
- Diagnose: event says
Container image "..." is not present with pull policy of Never(ErrImageNeverPull). Check the effective policy:kubectl get pod <pod> -n <ns> -o jsonpath='{.spec.containers[*].imagePullPolicy}'. - Adjacent gotcha: when you omit
imagePullPolicy, Kubernetes sets it from the reference —:latest(or no tag) defaults toAlways, a fixed tag or digest toIfNotPresent. The policy is fixed at create time and is not updated if the tag changes later, so a long-lived pod can keep using a stale cached image (kubernetes.io). - Fix: set
imagePullPolicy: IfNotPresent(and pre-pull the image to the node) orAlways, depending on whether you intend air-gapped behavior.
How Intellira diagnoses this
Intellira reads the pull error read-only and correlates it with the build that produced the tag — so when the manifest and the pushed tag disagree, it names the mismatch and the commit behind it instead of leaving you to compare by hand.
Sources
- Images — kubernetes.io
- Debug Pods — kubernetes.io
- Pull an Image from a Private Registry — kubernetes.io
- Well-Known Labels (kubernetes.io/arch) — kubernetes.io
By Intellira Engineering. AI-assisted draft, reviewed by the Intellira engineering team; claims cited inline; last verified 2026-06-02.