# Kubernetes pod stuck in ImagePullBackOff or ErrImagePull

The kubelet cannot pull the image, so the container never starts. ErrImagePull is the first failure and ImagePullBackOff is the wait between retries — neither says why. The registry's own error text, printed in the pod's Events, is what identifies the cause.

> Confidence: high · Verified: 2026-08-07 · Status: fresh · Source: https://knowbase.sh/k/kubernetes-imagepullbackoff

## Error signature

```
ImagePullBackOff
```

Codes: ImagePullBackOff, ErrImagePull

## Problem

A pod never reaches Running. Its status alternates between ErrImagePull and ImagePullBackOff, and the restart interval grows. kubectl logs returns nothing because no container was ever created — the failure happens before the image becomes a container, so the usual log-reading reflex gives you nothing to work with.

## Root cause

- **The image reference is wrong or the tag does not exist** _(primary)_
  - A typo in the repository, a tag that was never pushed, or a tag that has since been deleted or overwritten. The registry answers correctly; the reference is simply wrong.
  - How to tell: Events show 'manifest unknown' or 'not found', and pulling the exact same reference from your own machine fails identically
- **The registry is private and credentials are missing or wrong** _(common)_
  - No imagePullSecrets on the pod or its ServiceAccount, a secret in the wrong namespace, or credentials that have expired. Image pull secrets are namespaced, so one that works in staging does nothing in production.
  - How to tell: Events show '401 Unauthorized', 'pull access denied' or 'authentication required'
- **The registry rate-limited the pull** _(common)_
  - Docker Hub limits unauthenticated pulls to 100 per IPv4 address or IPv6 /64 subnet per six hours. A cluster behind one NAT address shares that budget across every node, so a busy cluster exhausts it without any single workload looking unusual.
  - How to tell: Events contain 'toomanyrequests' or 'You have reached your pull rate limit'
- **The node cannot reach the registry** _(common)_
  - DNS failure, an egress firewall, a proxy that needs configuring on the container runtime rather than the pod, or a private registry with no route from the node subnet.
  - How to tell: Events show 'dial tcp ... i/o timeout', 'no such host' or a TLS handshake failure
- **The image has no build for the node's architecture** _(edge)_
  - An amd64-only image scheduled onto an arm64 node. The reference resolves and credentials work, but the manifest list has no matching entry.
  - How to tell: Events show 'no matching manifest for linux/arm64' or a similar platform string

## Solution

1. Read the Events at the bottom of the pod description. The registry's own error text is there, and it names the cause; the pod status never does.

```bash
kubectl describe pod <pod-name> -n <namespace>
```

   Note: Look for the Failed event from the kubelet — it quotes the runtime's message verbatim.
2. Reproduce the pull from outside the cluster with the exact same reference. This separates a wrong reference from a cluster-side problem in one step.

```bash
crane manifest <registry>/<repo>:<tag> || docker pull <registry>/<repo>:<tag>
```

3. If the registry is private, create a pull secret and attach it to the pod in the same namespace as the pod.

```bash
kubectl create secret docker-registry regcred \
  --docker-server=<registry> \
  --docker-username=<user> \
  --docker-password=<password> \
  -n <namespace>
```

   Note: Then reference it under spec.imagePullSecrets, or attach it to the ServiceAccount so every pod in the namespace inherits it.
4. Wire the secret into the pod spec, or the kubelet will keep pulling anonymously.

```yaml
spec:
  imagePullSecrets:
    - name: regcred
  containers:
    - name: app
      image: <registry>/<repo>:<tag>
```

5. If the message mentions rate limiting, authenticate rather than retry. Unauthenticated pulls share a per-IP budget across the whole cluster, so retrying makes it worse. Mirroring hot images into your own registry removes the dependency entirely.
6. Fix the reference or the credentials, then replace the pod. Editing nothing and waiting does not help — the kubelet retries with the same failing spec, backing off up to five minutes between attempts.

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


**Verify:** kubectl describe pod shows a 'Successfully pulled image' event and the pod reaches Running; kubectl get pod reports a stable RESTARTS count.

**If that fails:** Where the registry is genuinely unreachable from the cluster — an air-gapped environment, for example — pre-load the image onto the nodes and set imagePullPolicy to IfNotPresent so the kubelet uses the local copy.

## Applies to

- Kubernetes: 1.20 and later — ImagePullBackOff is a Waiting-state reason surfaced by the kubelet, not a Pod phase.
- kubelet: 1.20 and later — Pull retry delay grows to a compiled-in ceiling of 300 seconds.
- Runtimes: containerd, CRI-O
- Platforms: linux/amd64, linux/arm64

## Not applicable to

- CrashLoopBackOff, where the image pulled successfully and the container starts then exits
- CreateContainerConfigError, where a referenced ConfigMap or Secret is missing
- ErrImageNeverPull, which means imagePullPolicy is Never and the image is absent from the node
- Pods stuck in Pending, which is a scheduling problem and never reaches the pull stage

## Evidence

1. [Images — ImagePullBackOff](https://kubernetes.io/docs/concepts/containers/images/) — The Kubernetes Authors (official-docs), read 2026-08-07
   Supports: The definition of ImagePullBackOff, that an invalid image name and a private registry without an imagePullSecret are its named causes, and that the retry delay grows to a compiled-in ceiling of 300 seconds.
   > The status ImagePullBackOff means that a container could not start because Kubernetes could not pull a container image ... which is 300 seconds (5 minutes)
2. [Pull an Image from a Private Registry](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/) — The Kubernetes Authors (official-docs), read 2026-08-07
   Supports: That a docker-registry Secret is the mechanism for authenticated pulls and that it is referenced from the pod through imagePullSecrets.
   > Create a Secret by providing credentials on the command line
3. [Docker Hub pull usage and limits](https://docs.docker.com/docker-hub/usage/pulls/) — Docker Inc. (official-docs), read 2026-08-07
   Supports: The unauthenticated pull ceiling of 100 per IPv4 address or IPv6 /64 subnet per six hours, which is why a NATed cluster exhausts the budget collectively.
   > Unauthenticated and Docker Personal users are subject to a 6-hour pull rate limit on Docker Hub.
4. [Debug Pods](https://kubernetes.io/docs/tasks/debug/debug-application/debug-pods/) — The Kubernetes Authors (official-docs), read 2026-08-07
   Supports: That describing the pod and reading its recent events is the first diagnostic step, which is where the registry's own error text appears.
   > The first step in debugging a Pod is taking a look at it. Check the current state of the Pod and recent events

## Confidence

high — The status definition, the retry ceiling and the named causes come from Kubernetes' own image documentation, and the pull-limit figures from Docker's published table. The per-cause discriminators are the runtime's own error strings as surfaced in pod events rather than claims any single document makes about diagnosis.

---

Retrieved from https://knowbase.sh/k/kubernetes-imagepullbackoff · knowbase · CC-BY-4.0
