EKS CrashLoopBackOff: How to Diagnose and Fix Restarting Pods

Your pod is showing CrashLoopBackOff and you need to know why. Start with kubectl logs —previous to get output from the container that just crashed. If that is empty or unclear, run kubectl describe pod and look at the Last State exit code. The exit code tells you the category of problem before you read a single line of logs.

Simple explanation

CrashLoopBackOff is not a crash itself. It is the status a pod shows when a container has crashed more than once and Kubernetes is waiting before trying again.

Think of it like a car that stalls every time you try to start it. After a few failed starts in a row, you stop cranking immediately and start waiting before the next attempt. The car has not fixed itself. The waiting is just Kubernetes not making things worse by hammering a broken container in a tight loop.

The sequence:

  1. Container starts and crashes
  2. Kubernetes restarts it
  3. It crashes again
  4. Kubernetes waits progressively longer before restarting (the “BackOff”)
  5. Pod shows CrashLoopBackOff during each waiting period

The underlying problem is whatever is causing the crash. CrashLoopBackOff is the messenger, not the cause.

At 7 or more restarts, backoff is capped at 5 minutes per attempt. You are not in a race against time. Take a moment to read the logs carefully rather than frantically deleting and recreating pods.

When to use this page

Use this page if kubectl get pods shows your pod in CrashLoopBackOff.

If your pod shows something else, you are likely on the wrong page:

Pod statusLikely problemWhere to look
CreateContainerConfigErrorMissing Secret or ConfigMapManaging Secrets in Kubernetes
ImagePullBackOffCannot pull the container imageCheck ECR permissions and image tag
PendingNo node available to schedule the podEKS Node Groups Explained
EvictedNode ran out of memory or diskCheck node-level metrics in Monitoring EKS

Fastest way to diagnose EKS CrashLoopBackOff

The three commands that matter most#

1. Get the previous container’s logs

kubectl logs <pod-name> --previous -n <namespace>

Without —previous, you are looking at the wrong container. The current container just started and has no output yet. Always use —previous to get the logs from the container that crashed.

2. Check the exit code

kubectl describe pod <pod-name> -n <namespace>

Scroll to Containers and find Last State. The exit code tells you the category of problem immediately. See the exit code reference section below.

3. Check cluster events

kubectl get events -n <namespace> --sort-by='.lastTimestamp' | grep <pod-name>

Events surface OOMKill notices, failed volume mounts, and probe failures that never appear in application logs.

Quick diagnostic checklist#

  • Did kubectl logs --previous show an error message or stack trace?
  • What is the exit code in Last State from kubectl describe pod?
  • Is RESTARTS above 5? The container will not recover without a fix.
  • Does Last State show Reason: OOMKilled? Memory limit is too low.
  • Does kubectl describe pod show Liveness probe failed or Startup probe failed in Events? Check probe config.
  • Is AWS_WEB_IDENTITY_TOKEN_FILE missing from the pod’s environment? IRSA or EKS Pod Identity is not configured correctly.

What to check based on what you see#

What you observeLikely causeJump to
Logs show stack trace or exceptionApplication startup errorApplication startup error
Exit code 127, logs emptyWrong binary pathWrong command or entrypoint
Exit code 137, OOMKilled in describeMemory limit exceededOOMKilled
Liveness probe failed in eventsProbe kills container before it is readyFailing liveness probe
Logs show NoCredentialProviders or AccessDenied at startupMissing IRSA or Pod Identity configIRSA misconfiguration
Logs empty, container exits in under 1 secondWrong entrypoint or immediate panicWrong command or entrypoint

How CrashLoopBackOff works

Each time a container crashes, Kubernetes restarts it. If it keeps crashing, restarting it instantly would waste CPU, flood logs, and put unstable code under continuous load. So Kubernetes slows down using exponential backoff.

Think of it like calling a friend who keeps not picking up. You try, wait 10 seconds, try again. After a few attempts you start waiting a minute between tries. You have not given up, you are just being realistic about how often to bother.

Restart countWait before next attempt
110 seconds
220 seconds
340 seconds
480 seconds
5160 seconds
6+300 seconds (5 minutes, capped)

The pod shows CrashLoopBackOff during each waiting period. The RESTARTS counter in kubectl get pods tells you how many times the container has crashed.

Kubernetes never stops retrying on its own. A pod in CrashLoopBackOff will keep restarting every 5 minutes indefinitely until you fix the underlying problem, delete the pod, or scale the deployment to zero.

CrashLoopBackOff vs OOMKilled vs CreateContainerConfigError vs ImagePullBackOff

StatusWhat it usually meansWhere to look firstBest first command
CrashLoopBackOffContainer crashes on startup, repeatedlyExit code in Last State plus previous logskubectl logs --previous
OOMKilledMemory limit exceeded, kernel killed the containerReason: OOMKilled in kubectl describe podkubectl top pod
CreateContainerConfigErrorMissing Secret or ConfigMap referenced in pod specEvents section in kubectl describe podkubectl describe pod
ImagePullBackOffCannot pull container image from registryECR permissions, image tag, registry authkubectl describe pod

A pod can show CrashLoopBackOff because it was OOMKilled. The Reason field in Last State tells you which one it is. If you see Reason: OOMKilled, jump to the OOMKilled section.

Exit code reference

Exit codeWhat it usually meansWhere to confirmWhat to check next
0Container exited cleanlyLast State in kubectl describe podIs the container supposed to stay running? In a Deployment, the app should not exit with code 0. Check for a logic bug or a misconfigured startup script.
1Application errorPrevious container logsLook for a stack trace or config error with kubectl logs --previous
2Misuse of shell or scriptPrevious logsUsually a shell scripting error in the entrypoint or startup script
127Command not foundLast State, often empty logsCheck command and args in pod spec; verify the binary exists in the image
137OOMKilled or SIGKILLReason: OOMKilled in describe podIncrease memory limit; check for a memory leak with kubectl top pod
139Segmentation fault (SIGSEGV)Last State exit codeUsually a bug inside C, C++, or Rust code; check for a core dump if available

Common causes

Application startup error#

Signature: Exit code 1 in Last State. Logs show a stack trace, exception, or “failed to initialize” message.

What it usually means: The application threw an uncaught error during startup. This could be a bad config value, a failed database connection, a missing dependency, or invalid input at boot time.

How to confirm: Run kubectl logs --previous. The error message is almost always in the last few lines.

First fix: Read the error and fix the code or configuration. If it says “cannot connect to database,” verify the database is reachable and that the connection string environment variable is correct. See Debugging VPC Connectivity Problems if the app cannot reach an RDS or other AWS endpoint.

Wrong command or entrypoint#

Signature: Exit code 127. Logs may show “command not found” or may be completely empty.

What it usually means: The command or args field in the pod spec references a binary that does not exist inside the container image.

How to confirm: Check the pod spec’s command and args. Verify the binary exists in the image:

docker run --entrypoint sh my-api:latest -c "ls /usr/local/bin/"

First fix: Correct the binary path in the pod spec, or rebuild the image so the binary exists at the expected path. See Kubernetes Pods for how command and args interact with the Dockerfile ENTRYPOINT and CMD.

Missing environment variable#

Signature: Exit code 1. Logs show something like KeyError: 'DATABASE_URL', Missing required env var: API_KEY, or ValueError: invalid literal.

What it usually means: The application requires an environment variable that was not injected into the pod.

How to confirm: Check the pod spec’s env and envFrom sections. Compare what is defined against what the application expects at startup.

First fix: Add the missing variable directly to the pod spec, or reference it from a Secret or ConfigMap. If the value is sensitive, store it in Secrets Manager and inject it using Managing Secrets in Kubernetes.

If the Secret or ConfigMap is referenced in the pod spec but does not exist in the cluster, the pod will show CreateContainerConfigError rather than CrashLoopBackOff.

Failing liveness probe#

Signature: Liveness probe failed in pod events. Container restarts periodically even though the application appears to be running.

What it usually means: The liveness probe is misconfigured. The most common cause is initialDelaySeconds being shorter than the application’s startup time, so the probe starts checking before the app is ready and kills it.

How to confirm:

kubectl describe pod <pod-name> -n <namespace> | grep -A 15 "Liveness"

First fix: Increase initialDelaySeconds to longer than the application’s worst-case startup time. If the app takes 15 seconds to start, set initialDelaySeconds: 30 as a safe starting point.

Readiness probes do not restart containers. Only liveness and startup probes can kill and restart a container. Readiness probes only affect whether the pod receives traffic from a Service. If you are chasing restarts by tuning readiness probe config, you are looking in the wrong place.

Failing startup probe#

Signature: Startup probe failed in pod events. Container restarts during the initial startup window before the app finishes initializing.

What it usually means: The startup probe’s failureThreshold or periodSeconds is not giving the application enough time to boot. Once a startup probe exceeds failureThreshold failures, Kubernetes kills and restarts the container.

How to confirm: Check kubectl describe pod for Startup probe failed in the Events section.

First fix: Increase failureThreshold or periodSeconds. A startup probe with failureThreshold: 30 and periodSeconds: 10 gives the app 300 seconds to become ready before Kubernetes kills it. Once the startup probe passes, the liveness probe takes over.

OOMKilled#

Signature: Last State: Terminated, Reason: OOMKilled, exit code 137.

What it usually means: The container exceeded the memory limit defined in the pod spec and the Linux kernel killed it.

How to confirm: Check kubectl describe pod for OOMKilled in Last State. Then check the memory limit in the pod spec:

resources:
  limits:
    memory: "128Mi"

Check actual current usage:

kubectl top pod <pod-name> -n <namespace>

For historical memory metrics and spikes, use CloudWatch Container Insights if it is enabled on your EKS cluster. See Monitoring EKS.

First fix: Either increase the memory limit, or find the memory leak. If usage grows steadily over time, the application has a leak. If it spikes and settles, the limit is simply set too low.

Node-level memory pressure looks different. If many pods together push the node over its memory capacity, the node-level OOM killer (not Kubernetes) may kill processes. In this case you may see pods with Evicted status rather than CrashLoopBackOff. Check node capacity with EKS Managed Node Groups and look for Evicted in kubectl get events.

IRSA misconfiguration#

Signature: Exit code 1. Logs show NoCredentialProviders, Unable to load credentials, AccessDenied, or similar AWS SDK errors before the application does any meaningful work.

What it usually means: The pod tried to initialize an AWS SDK client at startup and valid IAM credentials were not available because IRSA is not configured correctly.

Think of IRSA as a keycard system for your pod. The service account annotation is the keycard. The IAM trust policy is the door programmed to recognize that specific card. If the pod arrives without a keycard (missing annotation), or if the door does not recognize the card (wrong trust policy), access is denied and the application crashes before doing any real work.

The sequence that causes the crash:

  1. Pod starts
  2. Application initializes an AWS SDK client (to read from Secrets Manager, S3, DynamoDB, etc.)
  3. SDK cannot find valid credentials
  4. SDK throws an exception
  5. Application exits — CrashLoopBackOff

How to confirm: Check the service account annotation:

kubectl get serviceaccount <sa-name> -n <namespace> -o yaml

The annotation must be present:

annotations:
  eks.amazonaws.com/role-arn: arn:aws:iam::111122223333:role/my-app-role

Verify the pod spec references the service account:

kubectl get pod <pod-name> -n <namespace> -o yaml | grep serviceAccountName

Check that the credential env vars were injected:

kubectl exec <pod-name> -n <namespace> -- env | grep AWS

If AWS_WEB_IDENTITY_TOKEN_FILE is missing, the service account annotation is wrong or the pod spec does not reference the annotated service account.

The IAM role’s trust policy must also allow the specific service account to assume the role. See IAM Roles for Service Accounts for the full trust policy structure and common mismatches.

EKS Pod Identity misconfiguration or missing agent#

EKS Pod Identity is the modern alternative to IRSA, available on EKS 1.24 and later. Instead of annotating the service account, you create a Pod Identity association using the EKS console or CLI.

Signature: Same as IRSA. Exit code 1, AWS SDK credential errors in logs at startup.

How to confirm: Check whether the EKS Pod Identity Agent add-on is installed:

aws eks list-addons --cluster-name <cluster-name>

Look for eks-pod-identity-agent in the output. If it is missing, credentials are never injected into pods regardless of how associations are configured.

Check existing Pod Identity associations:

aws eks list-pod-identity-associations \
  --cluster-name <cluster-name> \
  --namespace <namespace>

First fix: Install the eks-pod-identity-agent add-on from the EKS console or via eksctl. Then create the association between the service account and the IAM role. See IAM Roles for Service Accounts for a comparison of IRSA vs Pod Identity and when to use each.

When the container crashes before you can debug

Some containers crash in milliseconds — too fast to exec into or capture logs from.

Override the command temporarily:

Edit the deployment to replace the container command with a sleep so the container stays running:

kubectl edit deployment <deployment-name> -n <namespace>

Change the container command:

command: ["/bin/sh", "-c", "sleep 3600"]

Then exec in and run the original start command manually to see what happens:

kubectl exec -it <pod-name> -n <namespace> -- /bin/sh
# Run the original startup command here and observe the output

Use an init container to capture environment state:

Add a debug init container that writes environment variables and filesystem state to a log before the main container starts. Read its output with:

kubectl logs <pod-name> -c init-debug -n <namespace>

Init container logs persist and are readable even after the main container crashes. See Logging in Kubernetes for more on how container logs are collected and forwarded in EKS.

Debugging a fast-crashing container? The sleep override is the fastest path to a shell. Once you are inside, run the original start command manually and you will see the exact error that the crash loop was hiding.

Common mistakes

  1. Running kubectl logs without —previous — you see the current container (usually empty immediately after restart) instead of the container that crashed.
  2. Setting initialDelaySeconds too short on liveness probes — the probe starts checking before the application is ready, kills the container, and the cycle repeats indefinitely.
  3. Confusing liveness and readiness probes — only liveness and startup probes restart containers. Readiness probe failures remove the pod from Service traffic but do not cause restarts. Chasing restarts by tuning readiness probe config is a dead end.
  4. Not specifying serviceAccountName in the pod spec — the IRSA annotation lives on the service account, but the pod spec must also reference that service account explicitly. If the pod uses the default service account, credentials are not injected unless the default service account itself is annotated (not recommended).
  5. Forgetting to install the EKS Pod Identity Agent add-on — if your team uses Pod Identity instead of IRSA, the agent must be running as an add-on. Without it, credentials are never mounted regardless of how associations are configured.
  6. Describing the Deployment instead of the Podkubectl describe deployment does not show crash details. Always describe and get logs from the specific pod name.

Summary

  • CrashLoopBackOff means a container keeps crashing. Use kubectl logs —previous and kubectl describe pod to find the exit code and last error message.
  • Exit code 137 = OOMKilled. Exit code 127 = command not found. Exit code 1 = application error. Exit code 0 = clean exit (the app should not exit if running as a Deployment).
  • Liveness and startup probes can restart containers when misconfigured. Readiness probes do not restart containers — they only affect traffic routing.
  • In EKS, missing IRSA or EKS Pod Identity configuration causes pods to crash if the application initializes AWS SDK clients at startup without valid credentials.
  • If the container crashes too fast to debug, temporarily override the command with a sleep and exec in to investigate manually.

Frequently asked questions

What does CrashLoopBackOff mean?

CrashLoopBackOff is a pod status that appears when a container has crashed more than once and Kubernetes is waiting progressively longer before restarting it again. The status is not itself the error — it means the container keeps failing to stay running. Run kubectl logs --previous and kubectl describe pod to find the actual cause.

How is CrashLoopBackOff different from OOMKilled?

OOMKilled is a specific crash reason — the kernel killed the container because it exceeded its memory limit. CrashLoopBackOff is the pod state after multiple crashes of any kind. A pod can enter CrashLoopBackOff because of OOMKilled, but also because of a startup error, missing environment variable, bad entrypoint, or failing liveness probe.

Can I get logs from a container that has already crashed?

Yes. Run kubectl logs <pod-name> --previous -n <namespace> to see logs from the most recently crashed container instance. Without --previous you see the current container logs, which are usually empty if the container just restarted.

How long is the CrashLoopBackOff backoff?

Kubernetes uses exponential backoff: 10 seconds, 20 seconds, 40 seconds, 80 seconds, 160 seconds, then caps at 5 minutes. The pod shows CrashLoopBackOff during each waiting period. At 7 or more restarts, expect roughly 5 minutes between attempts.

Why can missing AWS credentials cause CrashLoopBackOff in EKS?

If your application tries to initialize an AWS SDK client at startup — to read from Secrets Manager, S3, or DynamoDB — and the IAM credentials are missing or misconfigured due to a broken IRSA setup or missing EKS Pod Identity Agent, the SDK throws an exception and the application exits. Repeated exits produce CrashLoopBackOff.

Last verified: 13 May 2026 Cloud services change frequently. Verify details against official documentation before making infrastructure decisions.