Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Kubernetes & Helm By James Joyner IV · · 9 min read Last reviewed Jun 2026

Kubernetes Error Guide: 'CreateContainerConfigError' Missing ConfigMap or Secret

Quick answer

Fix the Kubernetes CreateContainerConfigError: diagnose missing ConfigMaps and Secrets, absent keys, wrong namespaces, ordering races, and bad envFrom/valueFrom references.

Part of the Kubernetes Pod Startup & CrashLoop Errors hub
  • #kubernetes
  • #troubleshooting
  • #errors
  • #configmap
Free toolkit

Stuck on this Kubernetes & Helm error? Get the free incident triage checklist

A one-page PDF — the exact steps to isolate, fix, and verify a production error like this one. No spam, unsubscribe anytime.

Overview

CreateContainerConfigError means the kubelet successfully pulled the image but could not assemble the container’s configuration, because something the pod spec references — a ConfigMap, a Secret, or a specific key inside one — does not exist. The pod is scheduled and the image is present, but the container never starts.

You will see this in kubectl get pods:

NAME                       READY   STATUS                       RESTARTS   AGE
api-6c8f9d7b54-q9w2r       0/1     CreateContainerConfigError   0          47s

And the underlying reason in the pod’s events:

Error: configmap "api-config" not found

Or, when the object exists but a referenced key does not:

Error: couldn't find key DATABASE_URL in ConfigMap shop/api-config

It occurs whenever a container references config via envFrom, env.valueFrom.configMapKeyRef, env.valueFrom.secretKeyRef, or a projected/volume mount, and that source is missing at container-create time. Unlike an image pull error, the scheduling and image are fine — only the config wiring is broken.

Symptoms

  • Pod status is CreateContainerConfigError (not Pending, not ImagePullBackOff).
  • kubectl describe pod shows configmap "<name>" not found or couldn't find key <KEY>.
  • The container never reaches Running; restarts stay at 0 because it never started.
  • The Deployment rolls out one bad pod and the rollout stalls.
kubectl get pods -n shop
NAME                       READY   STATUS                       RESTARTS   AGE
api-6c8f9d7b54-q9w2r       0/1     CreateContainerConfigError   0          47s
api-5b7c8d6f43-h2k8n       1/1     Running                      0          3h
kubectl describe pod api-6c8f9d7b54-q9w2r -n shop | sed -n '/Events/,$p'
Events:
  Type     Reason     Age               From     Message
  ----     ------     ----              ----     -------
  Normal   Pulled     12s (x4 over 47s) kubelet  Container image "registry.example.com/api:1.8.2" already present on machine
  Warning  Failed     12s (x4 over 47s) kubelet  Error: configmap "api-config" not found

Common Root Causes

1. envFrom references a ConfigMap/Secret that does not exist

The pod uses envFrom.configMapRef (or secretRef) naming an object that was never created (or was deleted/renamed).

kubectl get configmap -n shop
NAME                DATA   AGE
app-config          6      3h
kube-root-ca.crt    1      3h

The pod references api-config, but only app-config exists — a rename that was not applied to the Deployment.

2. A referenced key is missing inside an existing object

The ConfigMap/Secret exists, but configMapKeyRef/secretKeyRef names a key that is not present.

kubectl get configmap app-config -n shop -o jsonpath='{.data}' | tr ',' '\n'
{"APP_PORT":"8080"
"LOG_LEVEL":"info"
"FEATURE_FLAGS":"beta"}

The container asks for DATABASE_URL via configMapKeyRef, but the ConfigMap has no such key, producing couldn't find key DATABASE_URL.

3. The object is in the wrong namespace

ConfigMaps and Secrets are namespaced; a pod can only reference one in its own namespace. The object exists, but in default instead of shop.

kubectl get secret db-credentials --all-namespaces
NAMESPACE   NAME             TYPE     DATA   AGE
default     db-credentials   Opaque   2      5h

The pod runs in shop, so the shop-namespaced lookup fails even though the secret exists elsewhere.

4. The Secret/ConfigMap is created after the pod (ordering race)

In a fresh deploy, the pod can be created before its Secret (e.g., an external-secrets sync, a Helm hook, or a separate kubectl apply step has not run yet).

kubectl get secret api-tls -n shop
Error from server (NotFound): secrets "api-tls" not found

The pod is in CreateContainerConfigError now; once the secret lands, the kubelet retries and the container starts — but only if nothing else is wrong.

5. Missing optional: true for an intentionally absent source

If a reference is genuinely optional but the spec omits optional: true, Kubernetes treats the missing source as a hard error instead of skipping it.

kubectl get pod api-6c8f9d7b54-q9w2r -n shop -o jsonpath='{.spec.containers[0].envFrom}'; echo
[{"configMapRef":{"name":"feature-overrides"}}]

feature-overrides is meant to be present only in staging; without "optional":true on the ref, its absence in prod breaks container creation.

6. Typo in the env name, key, or valueFrom reference

A simple typo in the ConfigMap/Secret name or the key string sends the lookup to something that does not exist.

kubectl get pod api-6c8f9d7b54-q9w2r -n shop -o jsonpath='{range .spec.containers[0].env[*]}{.name}{" <- "}{.valueFrom.secretKeyRef.name}{"/"}{.valueFrom.secretKeyRef.key}{"\n"}{end}'
DB_PASSWORD <- db-credentials/postgres-pasword

The key postgres-pasword is a typo for postgres-password, so the lookup yields couldn't find key.

Diagnostic Workflow

Step 1: Confirm the status and read the exact error

kubectl get pod <POD> -n <NS>
kubectl describe pod <POD> -n <NS> | sed -n '/Events/,$p'

The event message tells you whether it is a missing object (... not found) or a missing key (couldn't find key ...).

Step 2: Identify every config source the container references

kubectl get pod <POD> -n <NS> -o yaml | grep -nE 'configMapRef|secretRef|configMapKeyRef|secretKeyRef|name:|key:|optional'

List the exact names and keys the spec expects.

Step 3: Verify the objects exist in the pod’s namespace

kubectl get configmap -n <NS>
kubectl get secret -n <NS>

A name in the spec that is not in this list is your missing object. If you suspect a namespace mistake, run with --all-namespaces.

Step 4: Verify the specific keys exist

kubectl get configmap <NAME> -n <NS> -o jsonpath='{.data}' | tr ',' '\n'
kubectl get secret <NAME> -n <NS> -o jsonpath='{.data}' | tr ',' '\n'

Compare the key names against the configMapKeyRef/secretKeyRef from Step 2 — watch for typos and case.

Step 5: Fix the source, then let the kubelet retry

# create the missing ConfigMap/Secret, or fix the reference, then:
kubectl rollout restart deploy/<DEPLOY> -n <NS>
kubectl get pods -n <NS> -w

The kubelet retries CreateContainerConfigError automatically, but a rollout restart guarantees a clean pod once the source is corrected.

Example Root Cause Analysis

A new api Deployment in namespace shop rolls out one pod stuck in CreateContainerConfigError.

kubectl describe pod shows the image is present and the failure is config:

Normal   Pulled  kubelet  Container image "registry.example.com/api:1.8.2" already present on machine
Warning  Failed  kubelet  Error: couldn't find key DATABASE_URL in ConfigMap shop/app-config

So the object exists; a key does not. Listing the spec’s references:

kubectl get pod api-6c8f9d7b54-q9w2r -n shop -o jsonpath='{range .spec.containers[0].env[*]}{.name}{" <- "}{.valueFrom.configMapKeyRef.name}{"/"}{.valueFrom.configMapKeyRef.key}{"\n"}{end}'
DATABASE_URL <- app-config/DATABASE_URL

The container wants the key DATABASE_URL from app-config. Checking what the ConfigMap actually contains:

kubectl get configmap app-config -n shop -o jsonpath='{.data}' | tr ',' '\n'
{"APP_PORT":"8080"
"LOG_LEVEL":"info"
"DB_URL":"postgres://db:5432/shop"}

The connection string is stored under DB_URL, but the Deployment references DATABASE_URL. The key name drifted between the config and the manifest.

Fix: align the names — either add a DATABASE_URL key to the ConfigMap or point the configMapKeyRef.key at DB_URL — then restart the rollout:

kubectl patch configmap app-config -n shop --type merge \
  -p '{"data":{"DATABASE_URL":"postgres://db:5432/shop"}}'
kubectl rollout restart deploy/api -n shop

The kubelet finds the key, the container is configured, and the pod reaches Running.

Prevention Best Practices

  • Apply ConfigMaps and Secrets before the workloads that reference them (Helm hooks, Kustomize ordering, or kubectl apply -f of config first) to avoid ordering races.
  • Keep config object names and keys under version control alongside the Deployment so a rename in one place forces the matching change in the other.
  • Mark genuinely optional references with optional: true so an absent source is skipped rather than fatal across environments.
  • Remember that ConfigMaps and Secrets are namespaced — a pod can only reference ones in its own namespace; never assume a default object is visible elsewhere.
  • Validate manifests in CI (e.g., kubeconform plus a check that every configMapKeyRef/secretKeyRef resolves) before merge. More patterns are in the Kubernetes & Helm guides.
  • Prefer envFrom with explicit, reviewed ConfigMaps over scattered per-key valueFrom references to reduce typo surface.

Quick Command Reference

# Confirm status and the exact failure message
kubectl get pod <POD> -n <NS>
kubectl describe pod <POD> -n <NS> | sed -n '/Events/,$p'

# List every config source the container references
kubectl get pod <POD> -n <NS> -o yaml | grep -nE 'configMapRef|secretRef|configMapKeyRef|secretKeyRef|name:|key:|optional'

# Do the objects exist (in this namespace)?
kubectl get configmap -n <NS>
kubectl get secret -n <NS>
kubectl get configmap <NAME> --all-namespaces

# Do the specific keys exist?
kubectl get configmap <NAME> -n <NS> -o jsonpath='{.data}' | tr ',' '\n'
kubectl get secret <NAME> -n <NS> -o jsonpath='{.data}' | tr ',' '\n'

# Fix the source, then force a clean pod
kubectl rollout restart deploy/<DEPLOY> -n <NS>
kubectl get pods -n <NS> -w

Conclusion

CreateContainerConfigError means the image is fine but the kubelet could not build the container’s config because a referenced ConfigMap, Secret, or key is missing. The usual root causes:

  1. envFrom/configMapRef/secretRef names an object that does not exist.
  2. The object exists, but a configMapKeyRef/secretKeyRef key is absent.
  3. The object lives in the wrong namespace (references are namespace-local).
  4. The Secret/ConfigMap is created after the pod — an ordering race.
  5. A genuinely optional reference is missing optional: true.
  6. A typo in the object name or key string sends the lookup nowhere.

Read the event message first: ... not found points to a missing object, couldn't find key ... points to a missing key — then verify names, keys, and namespace against the spec.

Free download · 368-page PDF

Fixed it? Get 500 Kubernetes & Helm & DevOps AI prompts — free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.

Did this fix your issue?

Free download · 368-page PDF

Get 500 Battle-Tested DevOps AI Prompts — Free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.