Kubernetes CrashLoopBackOff: How to Fix It
CrashLoopBackOff isn't an error in itself — it's Kubernetes telling you your container keeps starting and then dying. The fix is never the pod; it's finding why the process exits. Here's the exact path.
Your pod won't stay up:
NAME READY STATUS RESTARTS AGE
web-7d9f8c6b4-x2k9p 0/1 CrashLoopBackOff 5 3m
CrashLoopBackOff is not the disease — it's the symptom. It means your container starts, exits, and Kubernetes restarts it, over and over, waiting a little longer each time (the "back-off"). The container isn't broken to launch; the process inside it is exiting. Your entire job is to find out why it exits — and the pod itself never has the answer. The logs do.
Step 1: Read the logs of the crash that already happened
By the time you look, the current container may be mid-restart. You want the logs of the previous run — the one that just died:
kubectl logs <pod> --previous # the crashed container, not the fresh one
Nine times out of ten the reason is right there: a stack trace, "config file not found", "connection refused to database", "port already in use". Fix that, and the loop stops.
Step 2: Check the exit code and events
If the logs are empty, describe shows how it died:
kubectl describe pod <pod> # look at Last State → Exit Code and Events
- Exit Code 1 / non-zero — the app itself errored on startup (bad config, missing env var, unreachable dependency).
- Exit Code 137 — the container was OOMKilled: it used more memory than its limit. Raise the memory limit or fix the leak.
- Exit Code 0 that still loops — the process finished and exited cleanly, but it's not a long-running server. A one-shot script in a Deployment will loop forever; it belongs in a Job.
Cause: a failing liveness probe
A container can be perfectly healthy and still CrashLoop if its liveness probe is wrong — Kubernetes kills it for "failing" a health check that was never going to pass (wrong path, wrong port, or too short an initialDelaySeconds so it's killed before the app finishes booting). Check the probe in kubectl describe pod, and give a slow starter more time:
livenessProbe:
httpGet: { path: /healthz, port: 8080 }
initialDelaySeconds: 20 # don't kill it before it has booted
Cause: a missing env var, secret, or config
If the logs say something like "KeyError: DATABASE_URL" or "no such file", the container is missing something it expected. Confirm the ConfigMap/Secret exists and is actually mounted or referenced in the pod spec — a typo'd secretKeyRef name fails silently until the app reaches for the value.
The checklist
kubectl logs <pod> --previous— the crashed run almost always explains itself.kubectl describe pod <pod>— read Exit Code and Events.- Exit 137 = out of memory (raise the limit); exit 0 in a loop = use a Job, not a Deployment.
- Rule out a too-aggressive liveness probe (raise
initialDelaySeconds). - Confirm every env var, Secret, and ConfigMap the app needs is present and named correctly.
Frequently Asked Questions
How do I see the logs of a pod that already crashed?
Use kubectl logs <pod> --previous — it shows the logs of the previous, crashed container rather than the fresh one Kubernetes just started.
Does exit code 137 mean CrashLoopBackOff?
Exit code 137 means the container was OOMKilled (it exceeded its memory limit). If that keeps happening the pod ends up in CrashLoopBackOff — raise the memory limit or fix the leak.
What's the difference between CrashLoopBackOff and ImagePullBackOff?
CrashLoopBackOff means the container started and then crashed; ImagePullBackOff means the image never downloaded, so nothing ran at all.
Stop reading, start building
This pairs with a hands-on BytExplorer course — do it on your own machine and actually keep the skill.