How to fix Failed to pull image: secret not found in Kubernetes

KubernetesBEGINNERHIGHUpdated Dec 5, 2025· 95 views

This error occurs when a pod references an imagePullSecret that doesn't exist in its namespace. Fix it by creating the secret in the correct namespace and ensuring the name matches the pod specification.

Quick fix

Fixes Failed to pull image: secret not found

# List secrets in the namespace
kubectl get secrets -n <YOUR_NAMESPACE>

# Get detailed info about the secret
kubectl get secret <SECRET_NAME> -n <YOUR_NAMESPACE> -o yaml

# Verify it's the correct type
kubectl get secret <SECRET_NAME> -n <YOUR_NAMESPACE> -o jsonpath='{.type}'
# Should output: kubernetes.io/dockerconfigjson
  1. Verify the secret exists in the correct namespace
  2. Create the Docker registry secret
  3. Ensure pod specification references correct secret name
  4. Configure service account with imagePullSecrets
kubernetes — error
# List secrets in the namespace
kubectl get secrets -n <YOUR_NAMESPACE>
# Get detailed info about the secret
kubectl get secret <SECRET_NAME> -n <YOUR_NAMESPACE> -o yaml
# Verify it's the correct type
kubectl get secret <SECRET_NAME> -n <YOUR_NAMESPACE> -o jsonpath='{.type}'
# Should output: kubernetes.io/dockerconfigjson
Failed to pull image: secret not found

What this error means

The "Failed to pull image: secret not found" error means Kubernetes tried to use an imagePullSecret referenced in your pod spec, but couldn't find a secret with that name in the pod's namespace. ImagePullSecrets in Kubernetes are namespace-scoped resources. A secret created in namespace A is completely invisible to pods in namespace B. When your pod specification references a secret name that either doesn't exist or exists in a different namespace, the kubelet cannot retrieve the credentials needed to authenticate with the container registry. This error often occurs during multi-namespace deployments where secrets were created in the default namespace but pods run in application-specific namespaces.

Typical symptoms

  • Pod stuck in ImagePullBackOff status
  • Events show FailedToRetrieveImagePullSecret reason
  • Pods work in default namespace but fail in custom namespaces
  • Works when pulling public images, fails with private registries
  • Same deployment works in staging but fails in production namespace

Common causes

  1. Secret does not exist—never created or was deleted
  2. Secret created in different namespace than the pod (namespaces isolate secrets)
  3. Typo in secret name referenced in imagePullSecrets
  4. Wrong secret type (Opaque instead of kubernetes.io/dockerconfigjson)
  5. Secret deleted during cluster maintenance or namespace cleanup

How to fix "Failed to pull image: secret not found"

1Verify the secret exists in the correct namespace

Check if the secret exists in the pod's namespace:

bash
# List secrets in the namespace
kubectl get secrets -n <YOUR_NAMESPACE>

# Get detailed info about the secret
kubectl get secret <SECRET_NAME> -n <YOUR_NAMESPACE> -o yaml

# Verify it's the correct type
kubectl get secret <SECRET_NAME> -n <YOUR_NAMESPACE> -o jsonpath='{.type}'
# Should output: kubernetes.io/dockerconfigjson

If the secret doesn't exist, you'll see "Error from server (NotFound)".

2Create the Docker registry secret

Create the secret with proper credentials in the correct namespace:

bash
kubectl create secret docker-registry <SECRET_NAME> \
  --docker-server=<REGISTRY_URL> \
  --docker-username=<USERNAME> \
  --docker-password=<PASSWORD> \
  --docker-email=<EMAIL> \
  -n <YOUR_NAMESPACE>

Example for Docker Hub:

bash
kubectl create secret docker-registry dockerhub-creds \
  --docker-server=docker.io \
  --docker-username=myusername \
  --docker-password=mytoken \
  --docker-email=user@example.com \
  -n production

Verify creation:

bash
kubectl get secret dockerhub-creds -n production
3Ensure pod specification references correct secret name

Verify your pod spec uses the exact secret name:

yaml
apiVersion: v1
kind: Pod
metadata:
  name: private-image-pod
  namespace: production
spec:
  containers:
  - name: app
    image: private-registry.io/myapp:latest
  imagePullSecrets:
  - name: dockerhub-creds  # Must match secret name exactly

Check the current pod's imagePullSecrets:

bash
kubectl get pod <POD_NAME> -n <NAMESPACE> -o jsonpath='{.spec.imagePullSecrets}'
4Configure service account with imagePullSecrets

Add the secret to the service account so all pods using it inherit the credentials:

bash
kubectl patch serviceaccount default \
  -n <YOUR_NAMESPACE> \
  -p '{"imagePullSecrets": [{"name": "<SECRET_NAME>"}]}'

Or use YAML:

yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: default
  namespace: production
imagePullSecrets:
- name: dockerhub-creds

Verify:

bash
kubectl get serviceaccount default -n production -o yaml
5Replicate secrets across multiple namespaces

If you need the same secret in multiple namespaces:

bash
# Export from source namespace and apply to target
kubectl get secret my-secret -n source-namespace -o yaml | \
  sed 's/namespace: source-namespace/namespace: target-namespace/' | \
  kubectl apply -f -

Script to replicate to all namespaces:

bash
#!/bin/bash
SECRET_NAME="my-secret"
SOURCE_NS="default"

for ns in $(kubectl get namespaces -o jsonpath='{.items[*].metadata.name}'); do
  if [ "$ns" != "$SOURCE_NS" ]; then
    kubectl get secret "$SECRET_NAME" -n "$SOURCE_NS" -o yaml | \
      sed "s/namespace: $SOURCE_NS/namespace: $ns/" | \
      kubectl apply -f -
  fi
done
6Debug and validate the configuration

Comprehensive debugging:

bash
# View pod events for exact error
kubectl describe pod <POD_NAME> -n <NAMESPACE>

# Verify secret contains valid credentials
kubectl get secret <SECRET_NAME> -n <NAMESPACE> \
  -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d | jq .

# Check if serviceaccount has the secret
kubectl get serviceaccount <SA_NAME> -n <NAMESPACE> -o yaml | grep -A 5 imagePullSecrets

# Test with a debug pod
kubectl run debug-pod --image=busybox -n <NAMESPACE> \
  --rm -it --restart=Never \
  --overrides='{"spec":{"imagePullSecrets":[{"name":"<SECRET_NAME>"}]}}'

Advanced notes

Cross-Namespace Secret Limitation: Kubernetes does NOT support cross-namespace secret references. This is a fundamental security constraint—the kubelet cannot check RBAC for secrets in other namespaces.

Solutions for Multi-Namespace Environments:
- Manual replication: Create identical secrets in each namespace
- kubernetes-reflector: Auto-syncs secrets across namespaces with annotation-based rules
- Banzai Cloud IMPS: Distributes imagePullSecrets based on namespace/pod labels
- registry-creds: Propagates a single secret to all namespaces cluster-wide

Service Account vs Direct Pod Specification: Using service accounts is recommended—it centralizes management and automatically applies to all pods using that account. Direct pod specification requires updating every deployment when credentials change.

System Namespaces: Pods in kube-system, kube-public, and operator namespaces also cannot access secrets from other namespaces. System-level operators need their own credentials if pulling from private registries.

Frequently asked questions

What does "Failed to pull image: secret not found" mean?
The "Failed to pull image: secret not found" error means Kubernetes tried to use an imagePullSecret referenced in your pod spec, but couldn't find a secret with that name in the pod's namespace. ImagePullSecrets in Kubernetes are namespace-scoped resources. A secret created in namespace A is completely invisible to pods in namespace B.
How do I fix "Failed to pull image: secret not found"?
This error occurs when a pod references an imagePullSecret that doesn't exist in its namespace. Fix it by creating the secret in the correct namespace and ensuring the name matches the pod specification.
What causes "Failed to pull image: secret not found"?
Secret does not exist—never created or was deleted Secret created in different namespace than the pod (namespaces isolate secrets) Typo in secret name referenced in imagePullSecrets
Is the "Failed to pull image: secret not found" error serious?
Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.

Official resources & further reading