Skip to main content
DevOps Insightsguides & answers

Kubernetes · troubleshooting

CreateContainerConfigError

The kubelet could not assemble the container's configuration, so it never created the container. Usually a ConfigMap or Secret the container's environment refers to does not exist in the pod's namespace, or lacks the key named. runAsNonRoot checks and bad subPath mounts fail the same way. The real error is in the pod's events, not in kubectl describe's State section.

First published

New to this? Read what is actually happening first, then come back to the steps.

On this page · 9 sections

Before you start

  • kubectl access to the pod's namespace, including events and the ConfigMaps or Secrets the pod uses.
  • The pod's manifest, or the template of the Deployment or StatefulSet that owns it.
  • For the runAsNonRoot messages, a way to read the image's configured user: docker image inspect or crane config.

Run this first

step 1 of 3
kubectl get events -n <namespace> --field-selector involvedObject.name=<pod>,reason=Failed

Look for Error: followed by not found, couldn't find key, runAsNonRoot, or a mount message

The event message is the only place, besides the status field, that says what went wrong. kubectl describe's State section does not show it.

Work out which cause you have

A few questions to narrow the list. Every answer ends in a command that confirms or rules the cause out — this cannot see your cluster, so nothing here is a certainty until you have checked.

Narrow it down

0 answered · nothing is sent anywhere

What does the Failed event's message say after Error:?

kubectl get events --field-selector involvedObject.name=<pod>,reason=Failed

Cause space

4 of 4 still possible

  • A ConfigMap or Secret the environment refers to does not exist in the pod's namespaceCommon
  • The object exists but has no key of that nameCommon
  • runAsNonRoot is set and the container would run as root, or as a user the kubelet cannot checkOccasional
  • A volumeMount or subPath cannot be preparedRare

Nothing ruled out yet. Answer the question above and the branches your answer eliminates will strike through here.

Or diagnose it manually

In this order. The first command usually contains the whole answer.

  1. Step 1

    kubectl get events -n <namespace> --field-selector involvedObject.name=<pod>,reason=Failed

    The event message is the only place, besides the status field, that says what went wrong. kubectl describe's State section does not show it.

    Look for Error: followed by not found, couldn't find key, runAsNonRoot, or a mount message

  2. Step 2

    kubectl get pod <pod> -n <namespace> -o jsonpath='{.status.containerStatuses[*].state.waiting.message}'

    The same text without the Error: prefix, and still there after the events have expired. Use .status.initContainerStatuses for an init container.

    Look for The name of the missing object or key, or the user check that failed

  3. Step 3

    kubectl get configmap,secret -n <namespace>

    Lists what actually exists in the pod's namespace, which is the only namespace the pod can use.

    Look for The referenced name, spelled exactly as in the manifest

Every cause, and how to fix it

Ordered by how often each one turns out to be the answer.

A ConfigMap or Secret the environment refers to does not exist in the pod's namespace

Common

An env valueFrom or envFrom names an object that is not there: a typo, an object created in another namespace, one not yet applied, or a generated name with a suffix the reference does not use. Pods can only refer to objects in their own namespace.

Confirm

kubectl get events -n <namespace> --field-selector involvedObject.name=<pod>,reason=Failed
kubectl get configmap,secret -n <namespace>

Error: configmap "<name>" not found or secret "<name>" not found, and no object of that name in the pod's namespace

Fix

  • Create the object in the pod's namespace, or correct the name in the manifest.
  • If you create it, wait about 10 seconds: the kubelet retries the same pod and it starts. If you changed the manifest, the workload rolls out new pods instead.
  • Apply ConfigMaps and Secrets before, or together with, the workloads that use them.

The object exists but has no key of that name

Common

A configMapKeyRef or secretKeyRef names a key the object does not contain. Keys are case-sensitive, and DB_HOST and db_host are different keys. envFrom cannot fail this way, because it imports whatever keys exist.

Confirm

kubectl describe configmap <name> -n <namespace>
kubectl describe secret <name> -n <namespace>

The event says couldn't find key <key> in ConfigMap <namespace>/<name>, or in Secret; the key is absent from the Data list

Fix

  • Add the key to the object, or correct the key name in the reference.
  • Mark the reference optional only if the application genuinely works without that value.

runAsNonRoot is set and the container would run as root, or as a user the kubelet cannot check

Occasional

With runAsNonRoot: true the kubelet checks the user. runAsUser: 0 fails. With no runAsUser it reads the image: no USER counts as root, and a USER that is a name rather than a number cannot be verified, so both fail. Teams hit this when a namespace adopts the Restricted Pod Security Standard.

Confirm

kubectl get pod <pod> -n <namespace> -o jsonpath='{.status.containerStatuses[*].state.waiting.message}'
docker image inspect --format '{{.Config.User}}' <image>

image will run as root, image has non-numeric user, or runAsUser breaks non-root policy; and an empty or non-numeric USER in the image

Fix

  • Set securityContext.runAsUser to a non-zero UID the image's files allow. When runAsUser is set and non-zero, the kubelet does not inspect the image at all.
  • Or rebuild the image with a numeric user, such as USER 10001 or USER 10001:10001.
securityContext:
  runAsNonRoot: true
  runAsUser: 10001

In the container or pod spec. The UID needs read access to whatever the application loads at startup.

A volumeMount or subPath cannot be prepared

Rare

The container's mounts are built in the same step. A volumeMount naming a volume the pod does not declare, an absolute subPath, or a subPath the kubelet cannot create stops the container here, even though the volume itself mounted.

Confirm

kubectl get events -n <namespace> --field-selector involvedObject.name=<pod>,reason=Failed

cannot find volume … to mount into container …, must not be an absolute path, or failed to prepare subPath for volumeMount

Fix

  • Make every volumeMounts name match an entry under the pod's volumes.
  • Make subPath relative, and check that a subPathExpr does not expand to an absolute path.

Understanding it properly

Skip this if you are mid-incident — the working part of the page is above. Worth reading afterwards, because understanding the mechanism is what stops the next one.

In plain terms

Before starting a container, Kubernetes gathers everything it needs: environment variables from ConfigMaps and Secrets, files to mount, and which user to run as. If one of those pieces is missing or breaks a rule, the container is never started and the pod shows CreateContainerConfigError. The pod's events name the missing piece, and once you add it, the pod starts on its own within a few seconds.

Words used on this page

ConfigMap and Secret
Namespaced objects holding configuration and sensitive values. A pod can only use those in its own namespace.
valueFrom and envFrom
Two ways to set environment variables from them. configMapKeyRef and secretKeyRef take one named key; envFrom imports every key of the object.
optional
A field on those references. When true, a missing object or key is skipped and the variable is simply not set, instead of blocking the container.
runAsNonRoot
A securityContext setting. When true, the kubelet refuses to start a container that would run as user 0, and checks the image's user to decide.
Waiting reason
Why a container is not running yet. CreateContainerConfigError is one; it is not a pod phase, and the container has never existed.
What is actually happening

When the kubelet starts a container it first builds its configuration: environment variables, mounts, the user to run as. Any error in that step stops it before a container exists. The kubelet sets the container's waiting reason to CreateContainerConfigError, records a Warning event with reason Failed and the message Error: followed by the cause, and tries again.

Because no container ever runs, there are no logs and no restart count, and this is not CrashLoopBackOff. The kubelet retries the pod about every 10 seconds, re-reading ConfigMaps and Secrets each time, so creating the missing object or key lets the same pod start without deleting it.

kubectl describe pod shows State: Waiting and Reason: CreateContainerConfigError, but not the message. The cause is in the Events list at the bottom, or in the container's state.waiting.message. Several other failures also use the event reason Failed, so read the message, not the reason.

A missing ConfigMap or Secret used as a volume fails differently. The pod stays ContainerCreating with a FailedMount event such as MountVolume.SetUp failed for volume … : configmap … not found, because volumes are mounted before any container is configured. Only references from the container's environment, a runAsNonRoot check or a mount and subPath problem give CreateContainerConfigError.

How to tell this is your problem
WhereWhat you see
kubectl get pods STATUSCreateContainerConfigError, or Init:CreateContainerConfigError for an init container
kubectl describe pod, EventsWarning Failed … kubelet Error: configmap "app-config" not found
Event message, missing keyError: couldn't find key DB_HOST in ConfigMap <namespace>/<name>
Event message, runAsNonRootError: container has runAsNonRoot and image will run as root (pod: …, container: …)
kubectl describe pod, container StateWaiting, Reason: CreateContainerConfigError, and no message

How to know it is actually fixed

  • kubectl get pod shows Running, or the replacement pods do after a rollout.
  • No new Failed events for the pod in the last minute.
  • kubectl exec <pod> -- env shows the expected variables, without printing Secret values anywhere you would not paste a password.

Stopping it happening again

  • Deploy ConfigMaps and Secrets in the same release as the workloads that use them, so a reference cannot get ahead of its object.
  • Add a CI check that every configMapKeyRef and secretKeyRef names an object and key the release creates. A server-side dry run does not catch this, because the kubelet resolves those references only when it starts the container.
  • Build images with a numeric USER, so runAsNonRoot can be checked wherever the image runs.

Security considerations

  • When checking a Secret, use kubectl describe secret, which lists keys with byte counts only. kubectl get secret -o jsonpath='{.data}' prints the values, base64 encoded, which is as good as plain text.
  • Do not make a reference optional just to get the pod running. The container then starts without that setting, and an application that falls back to a default, an empty password or a disabled check is worse than one that does not start.
  • Fix a runAsNonRoot failure by running as a non-zero user, not by removing runAsNonRoot. The Restricted Pod Security Standard requires it, and it is what stops a container compromise from starting as root.
  • No RBAC change for the pod's service account fixes this. The kubelet reads ConfigMaps and Secrets for pods on its node through the Node authorizer, not with the pod's identity.

Sources

Behaviour described here is drawn from official documentation. Where a figure could not be confirmed on an official page it is attributed in the text rather than stated as canonical.

Did this get you to an answer?

No text box on purpose — please do not paste production logs anywhere

Something wrong or out of date? Report it