Guides
Detection guide

CrashLoopBackOff: How to Detect Crash Loops Before They Page You

By Sazabi Team

Last verified on Nov 8, 2026.

A crash loop is a process that starts, fails and starts again, repeatedly. In Kubernetes it surfaces as CrashLoopBackOff in the status column. The label is not an error itself. It tells you the kubelet is applying a delay between restarts because the container keeps failing. The Kubernetes docs say the delay grows exponentially, starting at 10 seconds (10s, 20s, 40s and so on), and is capped at 300 seconds. It resets once a container has run for 10 minutes without failing.

Crash loops hurt in two ways. The service runs below capacity while the loop continues, and the restarts hide the original cause, because each new container starts from scratch. The same shape shows up anywhere a supervisor restarts a failing process, such as a worker that exits every few minutes.

What the evidence looks like

At the cluster level you see a restart count that keeps growing and a waiting reason of CrashLoopBackOff. This example mirrors the format shown in the Kubernetes docs:

NAME               READY   STATUS             RESTARTS   AGE
worker-6c9d4f-x2k  0/1     CrashLoopBackOff   14         52m

Inside the pod description, the last state tells you how it died. The Kubernetes resource management docs show a terminated container with reason OOMKilled and exit code 137 for a container over its memory limit:

Last State:     Terminated
  Reason:       OOMKilled
  Exit Code:    137
Restart Count:  5

In application logs, the loop shows up as the same startup lines repeating, followed by the same fatal line, with a gap that lengthens as the backoff grows.

How to detect it

  1. Collect container state metrics. kube-state-metrics exposes kube_pod_container_status_restarts_total, kube_pod_container_status_waiting_reason and kube_pod_container_status_last_terminated_reason.
  2. Alert on the state and on the rate.
# Containers currently in CrashLoopBackOff
max by (namespace, pod, container) (
  kube_pod_container_status_waiting_reason{reason="CrashLoopBackOff"}
) == 1

# More than 3 restarts in 15 minutes
increase(kube_pod_container_status_restarts_total[15m]) > 3

# Last restart was an OOM kill
max by (namespace, pod, container) (
  kube_pod_container_status_last_terminated_reason{reason="OOMKilled"}
) == 1
  1. Add a log-side check for processes you run outside Kubernetes. Count startup messages per host.
SELECT host, service, count(*) AS starts
FROM app_logs
WHERE message = 'service starting'
  AND ts > now() - interval '30 minutes'
GROUP BY host, service
HAVING count(*) >= 4
ORDER BY starts DESC;
  1. Pair the alert with the reason. Query the last terminated reason and the exit code so the page tells the on-call person whether it was a memory kill, a bad exit or a failed probe.

Thresholds and pitfalls

Rate rules and state rules catch different things. During backoff the interval between restarts grows toward five minutes, so a rate rule can stay quiet for a pod that is still broken. The waiting-reason rule keeps firing. Use both, and add a for duration of a few minutes to the state rule so a single restart during a rollout does not page anyone.

Common false positives:

  • Rollouts. New pods restart while waiting for a dependency, then settle. A short for clause absorbs this.
  • Jobs and cron workloads that exit on purpose. Restart policy differs for them, so exclude completed jobs.
  • Init containers and sidecars. They can fail separately from the main container, so include them in the query if your pods depend on them.
  • Shared dependencies. When a database is down, every replica that needs it loops at once. Group alerts by service so you open one ticket, not forty.

Missing data is a pitfall too. If the metric disappears because the pod is rescheduled, the alert resolves. Keep the label set stable and test the rule by killing a staging pod on purpose.

What to do when it fires

Read the previous container's output, since the current one has barely started. The Kubernetes debugging docs give the command:

kubectl logs worker-6c9d4f-x2k --previous
kubectl describe pod worker-6c9d4f-x2k

The pod lifecycle docs list the usual causes: application errors that make the container exit, configuration errors such as missing environment variables, resource limits too low to start, health checks failing before the app is ready and failing liveness or startup probes. Work through them in that order, starting with the logs and the exit code. If the loop began with a deploy, roll back first and debug second.

Related guides: new kinds of error in your logs after a release often show the first crash, and capacity risks covers memory limits that are set too tight. A crashing worker also leaves data stale. The Kubernetes page covers kubectl access, and Fluent Bit covers shipping container logs.

With Sazabi

Sazabi detects this today with no setup: the Sazabi agent automatically sets up sensors for your project and maintains them over time. Crash Loop Alerts: An Investigated Issue When a Service Keeps Restarting covers what it catches.

Frequently Asked Questions

What does CrashLoopBackOff mean?

It means a container keeps failing and Kubernetes is delaying each restart. The delay grows exponentially and is capped at five minutes, according to the Kubernetes docs.

How do I see why a container crashed?

Run kubectl describe pod to read the last state and exit code, and kubectl logs with the --previous flag to read the output of the crashed container.

What does exit code 137 mean?

In the Kubernetes docs example, a container killed for exceeding its memory limit shows reason OOMKilled and exit code 137. Check the memory limit against real usage.

Why does the restart count stop growing but the pod is still unhealthy?

During backoff the container waits between attempts, so restarts slow down. The waiting reason still reads CrashLoopBackOff, which is why you should alert on the state as well as the restart rate.

Sources

  1. CrashLoopBackOff appears in kubectl status output, the exponential restart delay (10s, 20s, 40s and so on) is capped at 300 seconds and resets after 10 minutes of successful running, listed causes and investigation steps (accessed Nov 8, 2026)
  2. kube-state-metrics exposes kube_pod_container_status_restarts_total, kube_pod_container_status_waiting_reason and kube_pod_container_status_last_terminated_reason (accessed Nov 8, 2026)
  3. Memory limits are enforced by out-of-memory kills, and a terminated container shows reason OOMKilled with exit code 137 (accessed Nov 8, 2026)
  4. kubectl logs with the --previous flag shows the log of a container that has crashed (accessed Nov 8, 2026)