CrashLoopBackOff means a container in a Pod keeps crashing or exiting, so Kubernetes keeps restarting it, with a wait time between attempts that grows after every failure. The status is not a Kubernetes error, it is an honest report that your container is doing something it should not.
The good news: in the vast majority of cases, the cause sits right there in the Pod's logs or events, you just need to know where to look. The bad news: a CrashLoopBackOff can mean almost anything, from a simple typo in the command to a race condition with the database.
I run Kubernetes clusters in production and wrote the Kubernetes Practical Guide published by Rheinwerk Computing. You can find all my Kubernetes articles collected on the Kubernetes page.
What CrashLoopBackOff on a Kubernetes Pod actually tells you
CrashLoopBackOff is not a Pod phase, it is a reason derived from the state of a single container. The Pod's phase usually stays at "Running" the whole time, while a container inside it keeps switching between "Running" and "Terminated". The STATUS column of kubectl get pods then shows you the reason for the most recently failed container, not the state of the whole Pod.
The name also gives away the mechanics behind it: after every crash, Kubernetes waits a while before restarting the container, and that wait time doubles with every further failure, up to a cap of a few minutes. That protects the node from a broken container hammering it with endless restart attempts. For you, that means the longer a Pod has already been stuck in CrashLoopBackOff, the less often you catch a fresh restart happening live, so the cause is almost always already sitting in the previous logs. The exact relationship between Pod phase and container state is described in the Kubernetes documentation on the Pod lifecycle.
Diagnosis in three commands
Troubleshooting rarely takes more than three commands, run in this order. First an overview, then the details, then the logs of the most recently failed attempt. As a checklist for the real thing, in exactly this sequence:
- Read the events from
describe, they often name the reason outright.
- Pull the logs of the previous attempt with
--previous.
- Look at the exit code in the last state and interpret it.
- Check the configuration: ConfigMap, Secret, environment variables, paths.
- Check the probes, above all start deadlines that are too short.
- Check resources, memory limit and OOM kill last.
kubectl get pods -n my-app
kubectl describe pod my-app-7d9f8c6b5-x2k9p -n my-app
kubectl logs my-app-7d9f8c6b5-x2k9p -n my-app --previous
kubectl get pods shows you in the RESTARTS column how often a container has already restarted, and in STATUS the current reason. kubectl describe pod delivers the real substance: in the section for each container you find the current state and the last state with exit code, and at the very bottom the events with the chronological sequence, including whether an image could not be pulled or a volume could not be mounted. The --previous flag on kubectl logs is the crucial part: without it you see the logs of the current, possibly still empty attempt, with it you see the logs of the container that crashed last and therefore holds the actual error.
Reading exit codes: what the number means
The exit code in the last state from kubectl describe pod is often the fastest route to the cause. The table below shows the codes I run into most often in practice.
| Exit code |
Meaning |
Typical trigger |
| 0 |
process exited cleanly |
application without a long-running process, restartPolicy restarts it anyway |
| 1 |
general application error |
unhandled exception, missing configuration |
| 126 |
command found, but not executable |
missing execute permissions in the image |
| 127 |
command not found |
typo in command, wrong path |
| 137 |
terminated with SIGKILL (128 plus signal 9) |
OOMKilled or a forced deletion |
| 139 |
segmentation fault (128 plus signal 11) |
crash in native code, often a bug in the application |
| 143 |
terminated with SIGTERM (128 plus signal 15) |
regular, usually intentional shutdown |
An exit code of 137 is worth a second look in kubectl describe pod: if the reason there additionally says "OOMKilled", the container used more memory than its limit allowed. That is a good reason to revisit Kubernetes Requests and Limits Explained.
The most common causes and how to fix them
Most CrashLoopBackOff cases come down to a handful of recurring causes. The table below ranks them by how often I have run into them in my own clusters.
| Cause |
Tell |
Fix |
| Bug in the application itself |
exit code 1, stack trace in logs --previous |
fix the bug in the code, reproduce it locally |
| OOMKilled |
exit code 137, reason "OOMKilled" in events |
raise the memory limit or lower memory usage |
| Liveness probe configured too aggressively |
events show "Liveness probe failed" |
adjust the probe's timeout and thresholds |
| ConfigMap or Secret missing |
events show "CreateContainerConfigError" |
check the referenced name and namespace |
| wrong command or wrong path |
exit code 127 or 126 |
fix command and args in the manifest |
| missing permissions in the container |
non-zero exit code, error message about access rights |
check securityContext and file permissions in the image |
| race condition with a dependency |
application starts, crashes shortly after |
init container that waits for the dependency |
The last row is the one I run into most often, with applications that expect a database connection right at startup. If the database is not ready yet, the application crashes before a liveness probe could even kick in. A small init container that repeatedly checks the database and only lets the application through once it is up solves this more reliably than retry logic inside the application itself.
CrashLoopBackOff after a deployment or a GitOps sync
A special case I see regularly in production clusters: the crash loop only shows up after a new manifest has been rolled out, whether manually with kubectl apply or automatically through a GitOps sync. In that case, it is worth comparing against the previous version first, before you dig deep into the application itself.
With kubectl rollout undo deployment my-app -n my-app you undo the last rollout and get the cluster back into a working state right away. If your cluster runs on GitOps, the cleaner path is a revert of the faulty commit in the repository, so the desired state in Git and the actual state in the cluster match again. Only after that do you calmly analyze what actually broke in the new version, for example a changed environment variable or a new image that expects a different configuration.
How to prevent the next crash loop
Most CrashLoopBackOff cases become noticeably rarer with three simple habits. First, set realistic requests and limits, so a container is not killed by OOMKilled just because it briefly needs more memory than expected. Second, define liveness and readiness probes deliberately, with enough time for startup and without dependencies the application itself cannot resolve. Third, move waiting on external dependencies into an init container instead of handling it inside the application itself.
None of these three measures prevents every crash loop, but all three together noticeably shorten the time you spend troubleshooting going forward.
Frequently asked questions
What does CrashLoopBackOff mean exactly?
It means a container in a Pod keeps crashing or exiting, so Kubernetes keeps restarting it, with a growing wait time between attempts. It is not a distinct error state, it is a description of what is currently happening to the container.
How do I see the logs of a container that already crashed?
With kubectl logs <pod> --previous you get the logs of the last container that terminated, instead of the logs of the current, possibly still empty attempt. That is the most important command for actually seeing the real error message.
What does exit code 137 mean?
Exit code 137 is made up of 128 plus signal 9, which is SIGKILL. Most of the time an OOMKilled is behind it, the container used more memory than its limit allowed and was therefore killed hard. A look at the events from kubectl describe pod confirms it.
How long does Kubernetes wait between two restart attempts?
The wait time starts short and doubles with every further failure, up to a cap of a few minutes. If a container runs stably for longer, Kubernetes resets the counter. This growing gap is exactly why it is called CrashLoopBackOff.
Does a Pod in CrashLoopBackOff ever stabilize on its own?
Only if the cause resolves itself, for example because a dependency has become available in the meantime. A bug in the code or a missing configuration, on the other hand, does not go away on its own, there only analysis through describe and logs --previous followed by a targeted fix helps.
Where to go next
For everyday work with Pods, logs and shells inside containers, it is worth a look at kubectl Commands: The Essentials. How to configure probes so they prevent CrashLoopBackOff rather than trigger it is covered in more depth in Liveness and Readiness Probes Explained, and the right values for requests and limits to avoid OOMKilled crashes are in Kubernetes Requests and Limits Explained.
My suggestion for the next time you run into this: start with kubectl describe pod, read the events from bottom to top, and only then take a look at the application itself.
In full detail, with all the examples for the command line and for probes, this is covered in chapters 2 and 8 of my Kubernetes Practical Guide (Rheinwerk Computing).