Kubernetes Error Guide: 'Init Container Failed' — Unblock Init:Error
Fix an init container that exits non-zero in Kubernetes: read Init:Error and Init:CrashLoopBackOff, decode exit codes, and check init logs, dependencies, and mounts.
- #kubernetes
- #troubleshooting
- #errors
- #init-containers
Overview
Init containers run to completion, one at a time and in order, before any of a pod’s main containers are allowed to start. When an init container exits with a non-zero code, Kubernetes does not proceed to the app containers — it reports the pod as Init:Error (or Init:CrashLoopBackOff once the kubelet starts backing off) and holds there. The main container never boots, so nothing serves traffic even though the image and app themselves may be perfectly fine.
You will see this in the pod status column:
NAME READY STATUS RESTARTS AGE
api-6f8c4d7b9e-r3m8t 0/1 Init:CrashLoopBackOff 4 3m20s
The Init: prefix is the tell — the failure is in the initialization phase, not the app. Common causes are a bad command or missing binary in the init container, a dependency (database, config service, migration target) that is not ready when init runs, a bad volume mount the init step needs, or a script that simply exits non-zero. Because init containers respect the pod’s restartPolicy, a failing one loops just like a crashing app container, but the status keeps the Init: prefix so you know where to look.
Symptoms
- Pod status shows
Init:Error,Init:0/1, orInit:CrashLoopBackOffand never reachesRunning. READYis0/1and the main container has statusWaitingwith reasonPodInitializing.kubectl describe podlists the init container underInit Containerswith a non-zeroExit Code.- Logs from the init container (via
-c <init>) contain the failure message.
kubectl get pods -l app=api
NAME READY STATUS RESTARTS AGE
api-6f8c4d7b9e-r3m8t 0/1 Init:CrashLoopBackOff 4 3m20s
kubectl describe pod api-6f8c4d7b9e-r3m8t | grep -A8 'Init Containers'
Init Containers:
wait-for-db:
State: Terminated
Reason: Error
Exit Code: 1
Restart Count: 4
Common Root Causes
1. The init container waits on a dependency that is not ready
The classic init-container job is to block until a database, cache, or upstream service is reachable. If that dependency never comes up (wrong host, wrong port, service not deployed), the init step times out or fails and the pod is stuck.
kubectl logs api-6f8c4d7b9e-r3m8t -c wait-for-db
waiting for db.prod.svc.cluster.local:5432 ...
nc: bad address 'db.prod.svc.cluster.local'
timeout waiting for dependency, exiting 1
Here the Service name is wrong or the DB is not deployed. Fix the address or deploy the dependency, and the init step completes.
2. Bad command, missing binary, or wrong image
If the init container’s command/args points at a binary that does not exist in its image, the container exits immediately with a non-zero code — often exit 127 (command not found) or 126 (not executable).
kubectl logs api-6f8c4d7b9e-r3m8t -c run-migrations --previous
exec /usr/local/bin/migrate: no such file or directory
The migrate binary is not in the image, or the path is wrong. Use an image that contains the tool, or correct the command path.
3. Migration or setup script exits non-zero
An init container that runs a schema migration, seed, or config-render step fails if that command returns an error — a duplicate migration, a syntax error in a template, or a bad credential.
kubectl logs api-6f8c4d7b9e-r3m8t -c run-migrations
applying migration 0007_add_index.sql
ERROR: relation "orders" does not exist (SQLSTATE 42P01)
migration failed, exit status 1
The migration depends on a table that is not there yet. Fix the migration ordering or the target schema, then re-roll.
4. Bad volume mount or missing config the init step needs
Init containers often read from a mounted ConfigMap, Secret, or volume. If that mount is missing or the referenced object does not exist, the init step fails when it tries to read it.
kubectl describe pod api-6f8c4d7b9e-r3m8t | grep -A4 Events
Warning Failed 25s kubelet Error: configmap "bootstrap-config" not found
A missing ConfigMap surfaces as CreateContainerConfigError on the init container. Create the object or mark the reference optional: true.
5. Insufficient permissions in the init step
An init container running under a restrictive securityContext may be unable to write to a shared emptyDir, chown a path, or open a device — a frequent pattern where init exists specifically to prepare a volume for the main container.
kubectl logs api-6f8c4d7b9e-r3m8t -c fix-perms
chown: changing ownership of '/data': Operation not permitted
exit status 1
The init step needs the right runAsUser/fsGroup or capabilities to prepare the path. Adjust the securityContext.
Diagnostic Workflow
Step 1: Confirm it is an init-phase failure
kubectl get pod <POD> -n <NS> -o wide
An Init: prefix in the status confirms the failure is in an init container, not the app.
Step 2: Identify which init container failed
kubectl describe pod <POD> -n <NS>
The Init Containers block lists each one with its State, Reason, and Exit Code. Init containers run in order, so the first non-Terminated (Completed) one is the culprit.
Step 3: Read that init container’s logs
kubectl logs <POD> -n <NS> -c <INIT_CONTAINER>
kubectl logs <POD> -n <NS> -c <INIT_CONTAINER> --previous
You must pass -c <name> — plain kubectl logs <pod> targets the main container, which has not started. Use --previous if the init container has already restarted.
Step 4: Decode the exit code and events
kubectl get pod <POD> -n <NS> \
-o jsonpath='{.status.initContainerStatuses[0].lastState.terminated}'
kubectl get events -n <NS> --field-selector involvedObject.name=<POD> --sort-by='.lastTimestamp'
Map the code: 1/2 app/script error, 126 not executable, 127 command not found, 137 OOM/SIGKILL. Events reveal missing ConfigMaps/Secrets as CreateContainerConfigError.
Step 5: Verify the init command, mounts, and dependency
kubectl get pod <POD> -n <NS> -o jsonpath='{.spec.initContainers[0].command}{"\n"}'
kubectl get pod <POD> -n <NS> -o jsonpath='{.spec.initContainers[0].volumeMounts}{"\n"}'
kubectl get svc,configmap,secret -n <NS>
Confirm the command exists in the image, the mounts reference real objects, and the dependency the init step waits on is actually deployed.
Example Root Cause Analysis
A payments-api rollout hangs; every pod sits in Init:CrashLoopBackOff.
kubectl get pods -l app=payments-api -n prod
NAME READY STATUS RESTARTS AGE
payments-api-7b9d5c6f8a-9k4wq 0/1 Init:CrashLoopBackOff 5 4m02s
Describe shows the failing init container:
kubectl describe pod payments-api-7b9d5c6f8a-9k4wq -n prod | grep -A6 'Init Containers'
Init Containers:
wait-for-db:
State: Waiting (CrashLoopBackOff)
Last State: Terminated
Reason: Error
Exit Code: 1
Reading its logs:
kubectl logs payments-api-7b9d5c6f8a-9k4wq -n prod -c wait-for-db
waiting for postgres:5432 ...
nc: bad address 'postgres'
timeout after 60s, giving up
The init step targets the bare host postgres, but the database Service in this namespace is payments-db. The name never resolves, init times out, and the pod loops.
Checking the actual Service:
kubectl get svc -n prod | grep db
payments-db ClusterIP 10.96.14.22 <none> 5432/TCP 9d
Fix: point the init container at the correct Service name and re-roll:
kubectl set env deployment/payments-api -n prod DB_HOST=payments-db.prod.svc.cluster.local
kubectl rollout restart deployment payments-api -n prod
The init container connects, completes, and the main container finally starts.
Prevention Best Practices
- Always pass
-c <init-name>when debugging — the defaultkubectl logstargets the main container, which never started, and hides the real error. - Give dependency-wait init containers a bounded, logged timeout so a stuck pod tells you what it was waiting on instead of hanging silently.
- Reference dependencies by their fully qualified Service DNS name (
svc.<ns>.svc.cluster.local) to avoid namespace-resolution surprises. - Test init-container images and commands in CI the same way you test app images — a missing binary is a leading cause of
127/126init failures. - Make migrations and setup scripts idempotent so a retried init container does not fail on already-applied work.
- Confirm every ConfigMap, Secret, and volume the init step mounts exists in the namespace before rollout. See more in Kubernetes & Helm guides.
Quick Command Reference
# Confirm an init-phase failure
kubectl get pod <POD> -n <NS> -o wide
# Which init container failed, with exit code
kubectl describe pod <POD> -n <NS>
# The failing init container's logs (must pass -c)
kubectl logs <POD> -n <NS> -c <INIT_CONTAINER>
kubectl logs <POD> -n <NS> -c <INIT_CONTAINER> --previous
# Terminated state and exit code
kubectl get pod <POD> -n <NS> \
-o jsonpath='{.status.initContainerStatuses[0].lastState.terminated}'
# Events (missing ConfigMap/Secret show here)
kubectl get events -n <NS> --field-selector involvedObject.name=<POD> --sort-by='.lastTimestamp'
# Init command, mounts, and available dependencies
kubectl get pod <POD> -n <NS> -o jsonpath='{.spec.initContainers[0].command}{"\n"}'
kubectl get svc,configmap,secret -n <NS>
# Re-roll after a fix
kubectl rollout restart deployment <DEPLOY> -n <NS>
Conclusion
An Init:Error / Init:CrashLoopBackOff pod is blocked in its initialization phase — one init container exited non-zero, so the main containers are never started. The usual root causes:
- The init container waits on a dependency (DB, cache, service) that is unreachable.
- A bad command or missing binary makes the init container exit immediately (
127/126). - A migration or setup script returns a non-zero exit code.
- A missing ConfigMap/Secret or bad volume mount the init step needs (
CreateContainerConfigError). - Insufficient permissions stop the init step from preparing a shared volume.
Start by identifying which init container failed in kubectl describe pod, then read its logs with -c <name> — those two steps identify almost every init failure. For quick triage, the free incident assistant can turn an init describe dump into the likely root cause.
Download the Free 500-Prompt DevOps AI Toolkit
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.