Error reference

CrashLoopBackOff: How to Find Why Your Pod Keeps Restarting

Updated July 27, 2026

In short
CrashLoopBackOff means the container starts, exits, and Kubernetes is waiting before restarting it: with delays doubling from 10 seconds up to a 5-minute cap. It is a symptom, not a cause: the container is crashing for a concrete reason recorded in its logs and exit code. The single most useful command is 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.
start here
kubectl logs <pod-name> --previous
Diagnosis

Causes at a glance

CauseHow to recognize itFix
Application crashes on startuplogs --previous ends in a stack trace or fatal errorFix the app error; reproduce locally by running the same image
Missing or bad config/envLogs show "connection refused", a missing env var, or a bad flagCheck ConfigMaps, Secrets, and env with kubectl describe pod
Failing liveness probeEvents show "Liveness probe failed"; exit code 143Fix the endpoint or relax probe timing; use a startupProbe
OOMKilledLast State shows Reason: OOMKilled, exit code 137Raise memory limits or fix the leak: see the oomkilled guide
Wrong command or entrypointInstant 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

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> --previous
Step 2

Step 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 container
Step 3

Step 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 applies
Step 4

Step 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 300
Step 5

Step 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>
Beyond the one-off fix

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 Nexus

Common 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.