CrashLoopBackOff: How to Find Why Your Pod Keeps Restarting
Updated July 27, 2026
kubectl logs <pod-name> --previous, which prints the output of the crashed container instead of the fresh one. Pair it with kubectl describe pod for the exit code and events.kubectl logs <pod-name> --previousCauses at a glance
| Cause | How to recognize it | Fix |
|---|---|---|
| Application crashes on startup | logs --previous ends in a stack trace or fatal error | Fix the app error; reproduce locally by running the same image |
| Missing or bad config/env | Logs show "connection refused", a missing env var, or a bad flag | Check ConfigMaps, Secrets, and env with kubectl describe pod |
| Failing liveness probe | Events show "Liveness probe failed"; exit code 143 | Fix the endpoint or relax probe timing; use a startupProbe |
| OOMKilled | Last State shows Reason: OOMKilled, exit code 137 | Raise memory limits or fix the leak: see the oomkilled guide |
| Wrong command or entrypoint | Instant exit with code 127 or 126; "executable file not found" | Fix command/args in the pod spec or the image ENTRYPOINT |
What CrashLoopBackOff actually means
The kubelet restarts a crashed container immediately the first time, then backs off: 10s, 20s, 40s, doubling to a cap of 5 minutes. The pod spends most of its time in the Waiting state with reason CrashLoopBackOff, which is why the status looks stuck even though restarts are still happening. The backoff resets after a container runs cleanly for 10 minutes.
The status carries no information about why the container crashes: that lives in the previous logs and the exit code.
Step 1: read the logs of the crashed container
Plain kubectl logs shows the current (possibly just-restarted, still-empty) container. The --previous flag shows the output of the one that crashed: almost always where the stack trace is.
kubectl logs <pod-name> --previous
# multi-container pod:
kubectl logs <pod-name> -c <container-name> --previousStep 2: get the exit code and events
The exit code narrows the field instantly: 1 is a generic app error (read the logs), 137 is an OOM kill or SIGKILL, 143 is SIGTERM (often a liveness probe kill), 127/126 means the command is wrong or not executable. Events add the kubelet side of the story: probe failures, mount errors, backoff notices.
kubectl describe pod <pod-name>
# Last State: Terminated
# Reason: Error
# Exit Code: 1
# Events:
# Warning BackOff ... Back-off restarting failed containerStep 3: rule out the liveness probe
A misconfigured liveness probe produces a perfect imitation of a crashing app: kubelet kills the container (exit 143), restarts it, kills it again. Slow-starting apps get caught before they can serve the probe endpoint. Give slow starters a startupProbe so the liveness probe only takes over once the app is up.
startupProbe:
httpGet:
path: /healthz
port: 8080
failureThreshold: 30
periodSeconds: 5 # up to 150s to start before liveness appliesStep 4: check config, secrets, and dependencies
Apps that crash in the first second usually failed to read something: an env var that no longer exists, a Secret key renamed in the last release, a database that refuses connections. Compare what the pod actually received against what the app expects, and check whether a dependency it needs at boot is reachable.
kubectl exec <pod-name> -- env | sort
kubectl get configmap <name> -o yaml
kubectl get secret <name> -o jsonpath='{.data}' | head -c 300Step 5: debug interactively when logs are not enough
If the container dies too fast to inspect, run the image without its crashing entrypoint, or attach an ephemeral debug container to poke at the live pod.
# run the image with a shell instead of the failing command:
kubectl run debug --rm -it --image=<image> --command -- sh
# attach a debug container to the running pod (shares process namespace):
kubectl debug -it <pod-name> --image=busybox --target=<container-name>The worst crash loops start minutes after an automated change: an env var renamed, a Secret rotated, a flag removed. When AI agents make those changes, the "what changed right before this started" question is the whole investigation. Nexus captures every agent action via runtime hooks (which config was touched, by which agent, on whose instruction) so a crash loop at 2 a.m. comes with its own change history attached.
Explore Swfte NexusCommon questions
- Why is kubectl logs empty for my CrashLoopBackOff pod?
- Either you are reading the freshly restarted container instead of the crashed one (add --previous) or the process died before writing anything, which points at an exec-level failure: wrong command (exit 127), bad permissions (126), or logs going to a file instead of stdout.
- What does "back-off restarting failed container" mean?
- It is the event the kubelet emits while it waits between restart attempts. The container crashed, and Kubernetes is applying exponential backoff (10s doubling to 5 minutes) before trying again. It confirms the loop; the cause is in the logs and exit code.
- How long does CrashLoopBackOff wait between restarts?
- The delay starts at 10 seconds and doubles per crash (10s, 20s, 40s) capped at 5 minutes. If the container then stays up for 10 minutes, the backoff resets to zero.
- Can a failing liveness probe cause CrashLoopBackOff?
- Yes, and it is one of the most common causes. The kubelet kills any container that fails the probe (exit 143), and repeated kills enter the same backoff loop as real crashes. Slow-starting apps need a startupProbe or a longer initialDelaySeconds.
- How do I force a restart immediately instead of waiting out the backoff?
- Delete the pod (kubectl delete pod <pod-name>): the controller recreates it with a fresh backoff timer. Only useful after you have fixed the underlying cause; otherwise the new pod loops the same way.