Init:CrashLoopBackOff
Fix Init:CrashLoopBackOff: run kubectl logs pod -c init-name, then check the dependency it waits on, migrations that cannot rerun, and volume permissions.
Init:CrashLoopBackOff
Incident Overview
KubernetesKubernetes
Fix Init:CrashLoopBackOff: run kubectl logs pod -c init-name, then check the dependency it waits on, migrations that cannot rerun, and volume permissions.
medium fix·6 min read
By Vishvesh Patel·DevOps Engineer·Updated 21 September 2026
Init:CrashLoopBackOff Init:Error Init:0/2 Warning BackOff Back-off restarting failed container init-db in pod api-7d4f8c9b6-xk2mn
Do this first3 steps
Run these in order. Each one tells you what its output means before you change anything.
• Read the init container's logs, not the Pod's
kubectl logs without -c returns the main container, which has never started, so you get an unhelpful message about the container not being ready. The init container's name comes from kubectl describe pod.
• See how far the init sequence got
Init containers run strictly in order and each must exit 0 before the next starts. Init:0/2 means the first one has not finished, so only that one is worth looking at.
• Check the previous attempt if it is restarting too fast to catch
With CrashLoopBackOff the current container may not be running when you look. --previous returns the last terminated instance, which is the one that failed.
Init:CrashLoopBackOff means an init container is failing. Init containers run in order, before any app container, and each must exit 0 before the next one starts. One failing init container means the main container never runs at all.
The status tells you where you are:
kubectl logs my-pod -c init-db
Read the right logs
This is where most time gets lost:
That is the main container, which has never started. Name the init container:
--previous matters here. In CrashLoopBackOff the container is often not running when you look, so the current logs are empty and the useful output is in the last terminated instance.
kubectl logs my-pod
Pattern 1: Waiting for a dependency that will never arrive
The most common init container in the wild:
If postgres is not resolvable, this loops forever and the Pod sits in Init:0/1 rather than crashing, which is arguably worse because there is no error to read.
An empty ENDPOINTS means the Service exists and matches no ready Pods, so the name resolves and nothing answers. That is a different fix from the Service not existing at all.
Give the wait a bound so it fails visibly instead of hanging:
Two minutes then a clear failure, with progress in the logs throughout.
Worth asking whether the wait is needed at all. An application that retries its own database connection with backoff handles a restarting database mid-life too, which an init container cannot. The init container only covers the first few seconds of the Pod's existence.
initContainers:
- name: wait-for-db
image: busybox:1.36
command: ['sh', '-c', 'until nc -z postgres 5432; do sleep 2; done']Pattern 2: The migration that cannot be run twice
Init containers re-run on every Pod restart, and with multiple replicas they run concurrently, one per Pod. A migration tool without locking then has several processes racing on the same schema, and all but one fail.
Most tools handle this: Flyway, Liquibase and Rails all take a lock. If yours does not, a Job run once before the rollout is the correct shape, not an init container.
The same applies to anything non-idempotent. mkdir /data/foo fails the second time; mkdir -p /data/foo does not.
initContainers:
- name: migrate
image: myapp:1.4.2
command: ['./migrate', 'up']Pattern 3: Permissions on a volume
Without runAsUser: 0 the chown fails with Operation not permitted, and a securityContext at Pod level applies to init containers too. A cluster enforcing a restricted Pod Security Standard blocks runAsUser: 0 entirely, so the Pod will not even be admitted.
The better answer where the storage supports it is fsGroup, which lets the kubelet set ownership without a privileged container:
This works for most CSI drivers and removes the init container completely.
initContainers:
- name: fix-perms
image: busybox:1.36
command: ['sh', '-c', 'chown -R 1000:1000 /data']
volumeMounts:
- name: data
mountPath: /data
securityContext:
runAsUser: 0Resources apply differently
The scheduler uses the maximum of any single init container's request and the sum of the app containers' requests, not the total of everything. An init container with a large memory request can therefore make a Pod unschedulable in a way that is not obvious from reading the manifest.
Limits still apply individually, so an init container that exceeds its own memory limit is OOMKilled and you see Init:Error with exit code 137.
kubectl get pod my-pod -o jsonpath='{.status.initContainerStatuses[0].lastState.terminated}' | jqrestartPolicy governs init containers too
With restartPolicy: Always, a failed init container is retried with exponential backoff up to five minutes, hence CrashLoopBackOff. With restartPolicy: Never, which is common for Jobs, the whole Pod goes to Failed on the first init failure and stops. That is why the same broken init container loops forever in a Deployment and fails once in a Job.
A checklist
Frequently Asked Questions
Why does kubectl logs not show my init container's output?
Because kubectl logs defaults to the first app container, which in this situation has never started, so it returns a PodInitializing message instead of anything useful. Pass -c <init-container-name> to select the init container explicitly; the name is in kubectl describe pod under Init Containers. If the Pod is in CrashLoopBackOff the container may not be running at the moment you look, so add --previous to read the last terminated instance, which is the one that actually failed.
What is the difference between Init:Error and Init:CrashLoopBackOff?
Init:Error means the init container exited non-zero, and Init:CrashLoopBackOff means it has done so repeatedly and the kubelet is now delaying each retry with exponential backoff, up to five minutes. They are the same underlying failure at different stages. Which one you end up in depends on the Pod's restartPolicy: Always retries and reaches CrashLoopBackOff, while Never, common in Jobs, marks the Pod Failed after the first failure and stops.
Do init containers run again when a Pod restarts?
Yes. Every init container runs again, in order, each time the Pod starts, including after a node reboot or an eviction and reschedule. That makes them unsuitable for anything not safely repeatable. It also means that with several replicas they run concurrently, one per Pod, so a database migration in an init container has multiple copies racing unless the migration tool takes a lock. A Job run once before the rollout is the right shape for genuinely one-time work.
Why is my Pod stuck at Init:0/1 with no error?
The init container is running and not exiting, which usually means a wait loop whose condition never becomes true, such as until nc -z postgres 5432. Nothing has crashed, so there is no error to read; the Pod simply waits. Check whether the dependency is reachable, and in particular run kubectl get endpoints <service>, since a Service with no ready backends resolves as a name while nothing answers. Always give wait loops a bounded number of attempts and a non-zero exit so the failure is visible.
How do init container resource requests affect scheduling?
The scheduler computes the Pod's effective request as the larger of the maximum single init container request and the sum of the app container requests, because init containers run sequentially and never at the same time as the app containers. A single init container with a large memory request can therefore make the whole Pod unschedulable even when the app containers are small, which is hard to spot from reading the manifest. Limits are still enforced per container, so an init container exceeding its own memory limit is OOMKilled with exit code 137.
Reference and practice
Learn the underlying concept
Other Kubernetes errors
Free, comprehensive DevOps tutorials and learning roadmaps. Master Docker, Kubernetes, CI/CD, and more.
Get notified about new tutorials and features.
• Roadmaps
• Interview Prep
• Certifications
• Company
© 2026 DevOpsLesson. All rights reserved.
Need to practice this scenario?
Simulate this error condition and practice recovery commands safely in our in-browser terminal.