Kubernetes CrashLoopBackOff: Meaning, Diagnosis, and the 8 Fixes (2026)
CrashLoopBackOff explained — what it actually means, the kubectl diagnosis sequence, and the 8 root causes with fixes: config, probes, OOM, init containers, and more.
Short answer: CrashLoopBackOff means your container starts, crashes, and Kubernetes restarts it with growing delays (10s, 20s, 40s… up to 5 minutes) — it is not an error cause but a restart pattern. The actual cause is in the dead container's logs: kubectl logs <pod> --previous. The eight real causes: bad config/secrets, application exceptions, failing liveness probes, OOMKills, missing files or entrypoints, failed init containers, port/permission conflicts, and dependency unavailability at startup. Diagnosis sequence and all eight fixes below.
What CrashLoopBackOff actually means
Kubernetes always restarts failed containers (that's the feature). When a container exits non-zero, the kubelet restarts it; each successive crash doubles the backoff delay to a 5-minute cap. CrashLoopBackOff is simply the status Kubernetes shows while waiting out that backoff. Two implications: the pod may appear Running for seconds between crashes (check kubectl get pods repeatedly), and the "Back-off" delay is a symptom of repeated failure — the number you want is the exit code and the reason, not the status.
The diagnosis sequence (always in this order)
# 1. Status and restart count
kubectl get pod <pod> -n <ns>
# 2. The autopsy: Last State, Reason, Exit Code, Events
kubectl describe pod <pod> -n <ns>
# Last State: Terminated Reason: Error Exit Code: 1
# Events: Back-off restarting failed container
# 3. The dying container's own logs — 90% of answers live here
kubectl logs <pod> -n <ns> --previous --tail=100
# 4. If init containers are involved
kubectl logs <pod> -n <ns> -c <init-container-name> --previous
Related guideKubernetes Monitoring: The Complete 2026 Guide→
The 8 root causes and their fixes
| # | Cause | Signature in describe/logs | Fix |
|---|---|---|---|
| 2 | Application exception at startup | Exit 1; stack trace in --previous logs |
Fix the code path; test the same image locally with the same env |
| 3 | Liveness probe killing a slow starter | Liveness probe failed events; app logs show normal startup |
Add startupProbe or raise initialDelaySeconds; probe a cheap endpoint |
| 4 | OOMKilled during boot | Reason: OOMKilled, exit 137 |
JVM/heap vs container limit mismatch — raise limit or cap heap (-Xmx below limit) |
| 6 | Init container failing | Pod stuck Init:CrashLoopBackOff; init logs show the error |
Debug with logs -c <init> — usually a dependency wait or migration error |
| 7 | Port or permission conflict | bind: address already in use, permission denied |
Fix container port, run-as user (securityContext), or file ownership |
| 8 | Dependency unavailable at startup | Logs: connection refused to DB/queue/DNS | Add retry/backoff in app, or an init container that waits for the dependency |
The four most common, with exact commands
Missing config (cause 1):
Related guideKubernetes Integration→
kubectl describe pod <pod> | grep -A5 Events # "couldn't find key DATABASE_URL in Secret/app-secrets"
kubectl get secret app-secrets -o yaml # confirm the key name — typos are the classic
Startup crash (cause 2):
kubectl logs <pod> --previous --tail=200 # read the actual stack trace
# Reproduce locally with identical env:
docker run --rm -e DATABASE_URL=... <image>:<tag>
Probe-kills-starter (cause 3) — common with JVM apps that need 40s to boot but a liveness probe firing at 10s:
startupProbe: # let the app finish booting before liveness applies
httpGet: { path: /healthz, port: 8080 }
failureThreshold: 30
periodSeconds: 10 # 30 × 10s = 5 min of startup grace
Boot OOM (cause 4):
kubectl describe pod <pod> | grep -B2 OOMKilled
# If the app is Java: container limit 512Mi but JVM default heap ratios blow past it
# Fix: -XX:MaxRAMPercentage=75 or an explicit -Xmx below the limit
Preventing the next one
- Alert on it directly:
kube_pod_container_status_waiting_reason{reason="CrashLoopBackOff"} == 1— don't wait for users to report a deployment that never came up. - Rollouts that catch it: use progressive delivery (Argo Rollouts/Flagger) or at minimum
maxUnavailable: 0so a crashing new version never takes the old one down with it. - StartupProbe on every slow-starting service — the 60-second fix that eliminates the whole probe-misfire class.
- Centralized logs, because
kubectl logs --previousonly works while the pod object still exists; in a busy cluster the evidence rotates away.
FAQ
Q: What does CrashLoopBackOff mean in Kubernetes?
It means a container in the pod starts and crashes repeatedly, and Kubernetes is waiting out an exponentially growing delay (up to 5 minutes) before the next restart. It describes the restart pattern, not the cause — the cause is in the terminated container's logs (kubectl logs <pod> --previous) and the exit code in kubectl describe pod.
Q: How do I fix CrashLoopBackOff?
Diagnose first: kubectl describe pod (exit code + reason) and kubectl logs --previous (the error). Then match the cause: missing config/secret → create it; app exception → fix code; liveness probe misfire → add a startupProbe; OOMKilled → raise memory limit or cap app heap; bad entrypoint → fix command/args; failing init container → debug it with logs -c <init>.
Q: Why does my pod show Running then CrashLoopBackOff alternately?
Because the container genuinely starts, survives seconds-to-minutes, then crashes — Kubernetes restarts it after backoff, it starts again, crashes again. The Running windows are the crash cycles, not recovery. Watch RESTARTS climb in kubectl get pods -w and read --previous logs to see what's killing it each cycle.
Q: Can a liveness probe cause CrashLoopBackOff?
Yes — one of the most common causes. If the app starts slower than the probe's initialDelaySeconds + failureThreshold window, the kubelet kills a healthy-but-booting container, which restarts and gets killed again. The fix is a startupProbe (which suspends liveness checks until startup succeeds), not a longer liveness delay.
Q: How do I check CrashLoopBackOff logs after the pod is deleted?
You can't — --previous requires the pod object. This is why production clusters ship container logs to centralized storage (Loki, Elasticsearch, Guance, CloudWatch Logs). With centralized logs, the crashing container's output remains queryable by pod name long after the pod is gone.
Sources: Kubernetes documentation (container restart policy, probes, pod lifecycle). Verified 2026-08-07. Canonical page consolidating the "-fix" variant.
Contact us
Join the community
to join the community
Try Guance
Start online and pay only for what you use.
Get startedChoose a Guance plan