Back to blog

Debugging CrashLoopBackOff: Reading Pod Logs and Events Like a Pro

June 3, 2026 8 min read Kubexer Team
DebuggingPodsTroubleshootingLogs

CrashLoopBackOff is the status every Kubernetes operator learns to dread, and the one most often misread. It is not an error in itself — it is Kubernetes telling you a container keeps starting and exiting, so it is backing off before trying again. The real cause is somewhere else. This is a systematic way to find it.

What the status actually means

A Pod enters CrashLoopBackOff when its container exits (cleanly or by crashing) and the restart policy brings it back, repeatedly. Each failure increases the back-off delay (10s, 20s, 40s, up to 5 minutes), which is why a crashing Pod looks "stuck" — Kubernetes is deliberately waiting between attempts.

Step 1: read the events

Start with describe. The Events section at the bottom is where the kubelet records why it killed or failed to start the container.

kubectl describe pod web-7d9c-abc12

Look for clues: Back-off restarting failed container, OOMKilled, Liveness probe failed, Error: ImagePullBackOff. The reason here often ends the investigation immediately.

Step 2: read the logs — including the previous container

Current logs show the latest (possibly still-starting) attempt. The crash happened in the previous container, so reach for --previous:

kubectl logs web-7d9c-abc12 --previous

For multi-container Pods, target the container explicitly:

kubectl logs web-7d9c-abc12 -c app --previous

This is where you usually find the stack trace, the missing env var, or the "connection refused" that explains everything.

Step 3: check the exit code

The container status carries an exit code that narrows things fast:

kubectl get pod web-7d9c-abc12 -o jsonpath='{.status.containerStatuses[0].lastState.terminated}'
  • Exit 0 — the process completed and exited. Common when a long-running service is actually a one-shot script. Use a Job, or keep the process in the foreground.
  • Exit 1 / 2 — application error. Read the logs.
  • Exit 137 — SIGKILL, almost always OOMKilled. Raise the memory limit or fix the leak.
  • Exit 143 — SIGTERM; the container did not shut down within the grace period.

Common root causes

Misconfiguration

A missing or malformed ConfigMap/Secret value, a bad connection string, or a required env var that is not set. The app starts, fails to read config, and exits.

Failing health probes

An overly aggressive liveness probe kills a container that is simply slow to start. Add a startupProbe or raise initialDelaySeconds:

startupProbe:
  httpGet:
    path: /healthz
    port: 8080
  failureThreshold: 30
  periodSeconds: 5

Out of memory

Exit 137 with an OOMKilled event means the container exceeded its memory limit. Profile real usage, then set a realistic limit.

Dependency not ready

The app crashes because the database or a downstream service is not reachable yet. Add retries with backoff in the app, or an init container that waits for the dependency.

Step 4: get inside, if needed

If logs are not enough, debug a running or ephemeral container:

kubectl exec -it web-7d9c-abc12 -- sh
kubectl debug -it web-7d9c-abc12 --image=busybox --target=app

Doing this faster

The friction in CrashLoopBackOff debugging is context-switching: describe in one terminal, previous-logs in another, watching restart counts in a third. A tool like Kubexer collapses that loop — restart spikes surface as alerts, the events and previous-container logs are one click away, and you can search across containers for the one line that matters instead of scrolling. The methodology is the same; you just stop juggling terminals.

Wrapping up

Treat CrashLoopBackOff as a pointer, not a verdict. Events tell you the category, previous-container logs tell you the detail, and the exit code confirms the theory. Work them in that order and most crash loops resolve in minutes.