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.

Why the container is not createdPod specreferences configKubelet resolvesSecret, ConfigMapName or keydoes not existConfig errorcontainer not madeA missing Secret, ConfigMap, or key stops the container before Django starts.
  1. Read the event: kubectl describe pod <pod> | grep -A2 Warning names the missing object or key.
  2. Check it exists in the same namespace: kubectl get secret django-env -n production.
  3. Check the key: kubectl get secret django-env -n production -o jsonpath='{.data}' | jq 'keys'.
  4. Fix the reference or create the object; the pod retries automatically.
  5. 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.

what the event namesEvent saysCause and fixsecret not foundother namespace orname; create it therecouldn’t find key in Secretkey renamed or missing; add or fix refconfigmap not foundapplied after theDeployment; order applyExternalSecret not syncedoperator failed; check its statusThe container cannot be built until every reference resolvesdjango-deployment.com
The pod retries on its own once the missing object appears.

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.

how missing values behaveenvFrom secretRef✓short manifest✕missing key: no variable✕fails later inside DjangosecretKeyRef per key✓documents each setting✓missing key: pod waits✓clear event messageExplicit references fail early with a precise errordjango-deployment.com
Use explicit references for required settings and envFrom for optional extras.

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: true cannot 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

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.

Keep going