🔧 Error Fixes
· 2 min read
Last updated on

Kubernetes: ImagePullBackOff — How to Fix It


ImagePullBackOff

What causes this

Kubernetes tried to pull a container image and failed. After repeated failures, it backs off (waits longer between retries). The pod stays in ImagePullBackOff status until the issue is resolved. Common causes:

  • The image name or tag is wrong (typo, missing tag)
  • The image doesn’t exist in the registry
  • The registry requires authentication and credentials aren’t configured
  • The registry is unreachable (network issue, private registry behind a firewall)
  • You’re pulling from Docker Hub and hit the rate limit

Fix 1: Check the exact error

kubectl describe pod my-pod

Scroll to the Events section at the bottom. You’ll see the specific error:

  • repository does not exist — wrong image name
  • manifest unknown — wrong tag
  • unauthorized — missing credentials
  • timeout — network issue

Fix 2: Verify the image exists

# Test if you can pull it manually
docker pull myregistry.com/myimage:v1.2.3

# Check Docker Hub
docker pull nginx:latest

Common mistakes:

  • Missing the registry prefix: myimage:v1 vs myregistry.com/myimage:v1
  • Using :latest when no latest tag exists
  • Typo in the image name or tag

Fix 3: Add registry credentials

For private registries, create a pull secret:

kubectl create secret docker-registry regcred \
  --docker-server=myregistry.com \
  --docker-username=myuser \
  --docker-password=mypassword \
  --docker-email=me@example.com

Then reference it in your pod spec:

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
    - name: app
      image: myregistry.com/myimage:v1.2.3
  imagePullSecrets:
    - name: regcred

For a whole namespace:

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

Fix 4: Docker Hub rate limits

Docker Hub limits anonymous pulls to 100 per 6 hours. If you’re hitting this in CI or a cluster with many nodes:

# Create a secret with your Docker Hub credentials
kubectl create secret docker-registry dockerhub \
  --docker-server=https://index.docker.io/v1/ \
  --docker-username=yourusername \
  --docker-password=yourpassword

Or use a mirror/cache:

# In containerd config, add a mirror
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
  endpoint = ["https://your-mirror.example.com"]

Fix 5: Check network connectivity

If the node can’t reach the registry:

# SSH into the node and test
kubectl debug node/my-node -it --image=busybox
# Inside the debug container:
wget -O- https://myregistry.com/v2/

Common network issues:

  • Firewall blocking outbound HTTPS (port 443)
  • DNS not resolving the registry hostname
  • Proxy not configured on the node

Fix 6: Check the image architecture

If you built the image on an ARM Mac but your cluster runs on AMD64:

# Check the image architecture
docker manifest inspect myimage:v1 | grep architecture

Build for the right platform:

docker buildx build --platform linux/amd64 -t myimage:v1 .

How to prevent it

  • Always use specific image tags (:v1.2.3) instead of :latest — you’ll know exactly what version should be pulled
  • Set up imagePullSecrets at the namespace level so every pod gets credentials automatically
  • Use a container registry close to your cluster (same cloud provider) to avoid network issues
  • In CI, push the image and verify it exists before deploying to Kubernetes
  • Set up a registry mirror or cache to avoid Docker Hub rate limits