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.
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.
Check if the secret exists in the pod's namespace:
# 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/dockerconfigjsonIf the secret doesn't exist, you'll see "Error from server (NotFound)".
Create the secret with proper credentials in the correct namespace:
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:
kubectl create secret docker-registry dockerhub-creds \
--docker-server=docker.io \
--docker-username=myusername \
--docker-password=mytoken \
[email protected] \
-n productionVerify creation:
kubectl get secret dockerhub-creds -n productionVerify your pod spec uses the exact secret name:
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 exactlyCheck the current pod's imagePullSecrets:
kubectl get pod <POD_NAME> -n <NAMESPACE> -o jsonpath='{.spec.imagePullSecrets}'Add the secret to the service account so all pods using it inherit the credentials:
kubectl patch serviceaccount default \
-n <YOUR_NAMESPACE> \
-p '{"imagePullSecrets": [{"name": "<SECRET_NAME>"}]}'Or use YAML:
apiVersion: v1
kind: ServiceAccount
metadata:
name: default
namespace: production
imagePullSecrets:
- name: dockerhub-credsVerify:
kubectl get serviceaccount default -n production -o yamlIf you need the same secret in multiple namespaces:
# 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:
#!/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
doneComprehensive debugging:
# 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>"}]}}'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.
Failed to connect to server: connection refused (HTTP/2)
How to fix "HTTP/2 connection refused" error in Kubernetes
missing request for cpu in container
How to fix "missing request for cpu in container" in Kubernetes HPA
error: invalid configuration
How to fix "error: invalid configuration" in Kubernetes
etcdserver: cluster ID mismatch
How to fix "etcdserver: cluster ID mismatch" in Kubernetes
running with swap on is not supported
How to fix "running with swap on is not supported" in kubeadm