KubeGlanceDownload
CreateContainerConfigError and CreateContainerError: the four messages

troubleshooting

CreateContainerConfigError and CreateContainerError: the four messages

The kubelet could not build the container config — almost always a missing ConfigMap or Secret key. The message names the object that is missing.

· 9 min read

CreateContainerConfigError means the image was pulled successfully and the kubelet then failed to assemble the container’s configuration. In almost every real case that is an environment variable pointing at a ConfigMap or Secret that does not exist, or exists without the key you asked for.

The useful part is that the kubelet puts the exact object name in the message, so this error tells you the answer rather than hinting at it. Most people never read it because kubectl get pods truncates at the reason.

The fastest check

kubectl get pod <pod> -o jsonpath='{.status.containerStatuses[*].state.waiting.reason}{"\t"}{.status.containerStatuses[*].state.waiting.message}{"\n"}'
CreateContainerConfigError	configmap "nope" not found

That is the whole diagnosis. Across a namespace:

kubectl get pods -o custom-columns='NAME:.metadata.name,REASON:.status.containerStatuses[*].state.waiting.reason,MESSAGE:.status.containerStatuses[*].state.waiting.message'

The four messages, verified on 1.36

These are the actual strings, reproduced on a Kubernetes 1.36.1 cluster. Each maps to exactly one mistake.

MessageWhat you wrote
configmap "X" not foundconfigMapKeyRef or configMapRef naming a ConfigMap that does not exist in this namespace
secret "X" not foundsecretKeyRef or secretRef naming a Secret that does not exist in this namespace
couldn't find key K in Secret ns/XThe Secret exists. The key does not
container has runAsNonRoot and image will run as rootsecurityContext.runAsNonRoot: true on an image whose USER is root or unset

The first three are the same mistake in three costumes, and the namespace is the usual culprit: a ConfigMap reference resolves in the pod’s own namespace only. There is no cross-namespace form, and there is no error that says “wrong namespace” — you get not found.

The fourth one surprises people because it looks like a runtime failure and is not. The kubelet resolves runAsNonRoot by inspecting the image’s configured user before it creates the container, so an image that does not declare a non-root USER fails config generation. Setting runAsUser to a numeric UID satisfies it; setting runAsNonRoot: true alone does not, because the kubelet has nothing to check against.

Where in the startup path it fails

The reason string is precise about which step failed, and the steps run in a fixed order. Knowing the order means the reason alone tells you what already succeeded.

Each failure reason belongs to exactly one step. CreateContainerConfigError means the image is already on the node.

That has a practical consequence worth internalising: CreateContainerConfigError proves the image pull worked. If you are looking at this error, the registry, the credentials and the tag are all fine, and you can stop checking them. When the pull is the problem you get a different reason entirely, covered in ImagePullBackOff and ErrImagePull.

What does not produce this error

Two things get attributed to CreateContainerConfigError constantly and do not cause it. Both were tested on 1.36.1.

A missing ConfigMap or Secret used as a volume. This does not reach config generation at all — the mount fails first, so the pod sits in ContainerCreating with a FailedMount event:

Warning  FailedMount  0s (x7 over 32s)  kubelet  MountVolume.SetUp failed for volume "cfg" : configmap "absent-cm" not found

Same root cause, different reason, and crucially a different place to look: the events, not the container status. A pod stuck in ContainerCreating with no container status message is nearly always a volume.

A command or binary that does not exist. That is RunContainerError, which happens one step later — the config was built fine and the runtime refused to start the process:

RunContainerError  failed to create containerd task: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: exec: "/no/such/binary": stat /no/such/binary: no such file or directory

The wall of runtime text is unpleasant but the tail of it is the answer, and it is always the tail. The same is true for a hostPath mounted at a path whose parent is a file rather than a directory, which produces the same reason with a securejoin message instead.

CreateContainerError — without Config — is the third of the family and the rarest. It comes from the runtime rejecting an otherwise valid config, most often a container name still in use after an abrupt kubelet restart. If you see it and the message mentions a name conflict, it usually clears itself on the next sync.

Fixing it

Name the object the message named. The error is not generic:

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

The second one lists the keys present without printing the values, which is what you need for couldn't find key.

Make optional references optional. If a config value genuinely may be absent, say so, and the container starts without it instead of blocking:

env:
  - name: FEATURE_FLAG
    valueFrom:
      configMapKeyRef:
        name: features
        key: beta
        optional: true

This is the fix for the classic ordering failure, where a Helm chart creates the Deployment before the ConfigMap and the first pod dies on a race that resolves itself thirty seconds later.

Check the namespace before the name. A ConfigMap that exists in default and a pod running in prod produce not found, which reads like a typo and is not.

Preventing it

  • The pod does not retry into a backoff for this. Unlike a crash loop, the kubelet keeps retrying config generation at the sync interval, so a pod fixed by creating the missing ConfigMap recovers on its own without a restart. You do not need to delete the pod, and deleting it hides how long it was broken.
  • Reference keys, not whole objects, where you can. configMapKeyRef fails with a message naming the key. envFrom with a missing object fails with a message naming only the object, which is less information for the same mistake.
  • Treat runAsNonRoot as an image contract. If your base image does not set a numeric USER, the policy will fail every pod that uses it, and the failure arrives at deploy time rather than build time.

For the errors that come after this one — the container starts and then dies — see how to fix CrashLoopBackOff, and for reading the STATUS column that reports all of these, how kubectl computes a pod’s STATUS.

The waiting-state message is the answer, and it is the field most tools hide. KubeGlance is a native Kubernetes client for iPhone and iPad, with a full Mac app on the same core — container states and their messages without a jsonpath expression.

Get KubeGlance
#createcontainerconfigerror #configmap #secret #pods #troubleshooting

The Kubernetes dashboard that fits in your pocket

KubeGlance is a native Kubernetes client for iPhone and iPad — the real dashboard, not a companion — with a full Mac app on the same core. Pods, workloads, logs and events, straight from your kubeconfig.

Download KubeGlance