Fix Kubernetes CreateContainerConfigError for Django Pods
Fix Kubernetes CreateContainerConfigError for Django pods: find the missing Secret, ConfigMap, or key in the pod events, create it in the right namespace, fix envFrom and secretKeyRef names, and order resources so deploys do not race their config.
Problem statement
A pod sits in a waiting state and never starts the Django container:
NAME READY STATUS RESTARTS AGE
web-5f7c9d6b8-q8r2t 0/1 CreateContainerConfigError 0 2m
The image pulled fine, but Kubernetes could not build the container's configuration. Almost always, the pod references a Secret or ConfigMap, or a key inside one, that does not exist in the pod's namespace. Kubernetes refuses to start a container with incomplete environment variables or volumes, which is better than Django starting without its SECRET_KEY or database password.
- Read the event:
kubectl describe pod <pod> | grep -A2 Warningnames the missing object or key. - Check it exists in the same namespace:
kubectl get secret django-env -n production. - Check the key:
kubectl get secret django-env -n production -o jsonpath='{.data}' | jq 'keys'. - Fix the reference or create the object; the pod retries automatically.
- Mark truly optional references with
optional: true, and keep required ones required.
Step-by-step solution
1. Find the exact reference
kubectl describe pod web-5f7c9d6b8-q8r2t -n production | grep -A2 -i warning
Typical messages:
Error: secret "django-env" not found
Error: couldn't find key DATABASE_URL in Secret production/django-env
Error: configmap "django-config" not found
The message names the object and, for key errors, the key.
2. Check namespace and spelling
Secrets and ConfigMaps are namespaced. A Secret created in default is invisible to pods in production:
kubectl get secrets -A | grep django-env
Names are case-sensitive and must match exactly, including in Helm templates that add release-name prefixes such as myapp-django-env.
3. Fix key references
With individual variables:
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: django-env
key: DATABASE_URL
the key must exist in the Secret. With envFrom, every key becomes a variable and a missing Secret fails the pod, but missing keys simply produce no variable, which Django then reports as KeyError or an ImproperlyConfigured error at startup:
envFrom:
- secretRef:
name: django-env
- configMapRef:
name: django-config
Prefer explicit secretKeyRef for critical settings so mistakes fail before the container starts.
4. Order resources in deploys
Applying a Deployment before its Secret creates a window where pods fail. kubectl apply -f dir/ applies files in name order, and Helm installs Secrets and ConfigMaps before Deployments. If secrets come from an operator such as External Secrets, the ExternalSecret must sync before pods start:
kubectl get externalsecret -n production
kubectl describe externalsecret django-env -n production
A SecretSyncedError status means the operator could not read the backing store, often an IAM or path problem.
5. Use optional references deliberately
- name: SENTRY_DSN
valueFrom:
secretKeyRef:
name: django-env
key: SENTRY_DSN
optional: true
Optional is right for features that can be off. Do not mark SECRET_KEY or DATABASE_URL optional; you want the pod to stop rather than start broken.
Explanation
Before creating a container, the kubelet assembles its environment and volume mounts from the pod spec. Each secretKeyRef, configMapKeyRef, envFrom, and secret or ConfigMap volume is resolved through the API server. If a required object or key is missing, the kubelet cannot produce a valid container configuration and reports CreateContainerConfigError. It retries periodically, so creating the object fixes the pod without further action.
Edge cases / notes
- Immutable Secrets. Secrets marked
immutable: truecannot be updated in place; create a new name and roll the Deployment. - Updates do not restart pods. Changing a Secret used as environment variables does not affect running pods. Roll the Deployment after changes.
- RBAC. The kubelet reads Secrets with node credentials, not the pod's service account, so RBAC on the service account does not cause this error.
Next steps
- Organize configuration with Kubernetes Secrets and ConfigMaps for Django.
- Sync secrets from a manager with Use External Secrets Operator With Django.
- If the container starts and then crashes, see Fix Kubernetes CrashLoopBackOff for Django.
FAQ
Is CreateContainerConfigError the same as CrashLoopBackOff?
No. With CreateContainerConfigError, the container never starts. CrashLoopBackOff means it started and exited.
Do I need to restart the pod after creating the Secret?
No. The kubelet retries and starts the container once the reference resolves.
Can a pod read a Secret from another namespace?
No. Copy it into the pod's namespace or use an operator that syncs it.
Why does it work in staging but not production?
The Secret or key exists only in the staging namespace. Compare kubectl get secret -o yaml key names between environments.