Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Kubernetes & Helm By James Joyner IV · · 9 min read

Kubernetes Error Guide: 'Readiness probe failed: context deadline exceeded' Probe Timeouts

Fix Kubernetes probe timeouts: 'Readiness probe failed: context deadline exceeded' and liveness restart loops via initialDelaySeconds, timeoutSeconds, and paths.

  • #kubernetes
  • #troubleshooting
  • #errors
  • #probes

Overview

A context deadline exceeded probe failure means the kubelet sent a readiness or liveness probe request to the container and did not get a response before the probe’s timeoutSeconds elapsed. For a readiness probe this keeps the pod out of Service endpoints (0/1 READY); for a liveness probe it counts toward failureThreshold and, once exceeded, the kubelet restarts the container — sometimes in a loop.

You will see this on the pod’s events:

Warning  Unhealthy  12s  kubelet  Readiness probe failed: Get "http://10.1.4.22:8080/healthz": context deadline exceeded (Client.Timeout exceeded while awaiting headers)

Or, for liveness:

Warning  Unhealthy  8s   kubelet  Liveness probe failed: Get "http://10.1.4.22:8080/healthz": context deadline exceeded
Normal   Killing    8s   kubelet  Container app failed liveness probe, will be restarted

It occurs whenever a probe’s response time exceeds its timeout: at startup if the app is slow to initialize, under load if the handler is contended, or continuously if the probe targets a heavy/blocking endpoint. The same spec can pass on an idle pod and fail under traffic, which makes these failures intermittent.

Symptoms

  • Pod is Running but 0/1 READY and never enters Service endpoints.
  • Events show Readiness probe failed: ... context deadline exceeded.
  • Liveness failures show Killing and restart counts climbing.
  • The app logs no error of its own — it simply did not answer in time.
kubectl get pod checkout-6c8d7b5f4-q9w2r
NAME                       READY   STATUS    RESTARTS      AGE
checkout-6c8d7b5f4-q9w2r   0/1     Running   3 (45s ago)   4m
kubectl describe pod checkout-6c8d7b5f4-q9w2r | grep -A6 Events
Events:
  Type     Reason     Age                From     Message
  ----     ------     ----               ----     -------
  Warning  Unhealthy  30s (x6 over 2m)   kubelet  Readiness probe failed: Get "http://10.1.4.22:8080/ready": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
  Warning  Unhealthy  15s (x4 over 90s)  kubelet  Liveness probe failed: Get "http://10.1.4.22:8080/ready": context deadline exceeded
  Normal   Killing    15s                kubelet  Container app failed liveness probe, will be restarted

Common Root Causes

1. App is slow to start; initialDelaySeconds / timeoutSeconds too low

The container needs longer to warm up than the probe allows, so the first probes time out before the app is listening.

kubectl get pod <POD> -o jsonpath='{.spec.containers[0].readinessProbe}{"\n"}' | jq .
{
  "httpGet": { "path": "/ready", "port": 8080 },
  "initialDelaySeconds": 2,
  "timeoutSeconds": 1,
  "periodSeconds": 5,
  "failureThreshold": 3
}

A 2s delay with a 1s timeout is far too tight for an app that takes 20s to load. A startupProbe or larger delay/timeout fixes it.

2. Endpoint is slow or overloaded under load

The handler responds quickly when idle but blows past timeoutSeconds when the pod is saturated, so readiness flaps in and out under traffic.

kubectl exec <POD> -- sh -c 'time wget -qO- http://localhost:8080/ready'
OK
real    0m2.84s

A 2.84s response against a 1s timeoutSeconds will fail every time the pod is busy.

3. Wrong probe path or port

The probe targets a path that returns a non-2xx (or a port nothing listens on), so it never succeeds — sometimes surfacing as a timeout when the port is filtered.

kubectl get pod <POD> -o jsonpath='{.spec.containers[0].readinessProbe.httpGet}{"\n"}'
kubectl exec <POD> -- sh -c 'wget -qO- -S http://localhost:8080/healthz 2>&1 | head -3'
{"path":"/healthz","port":8080}
wget: can't connect to remote host: Connection refused

The app actually serves health on port 9090 at /health, not 8080/healthz.

4. Probe hits a blocking or heavy handler

The health endpoint runs expensive work (full DB scan, cache warm, template render) so it is inherently slow and intermittently exceeds the deadline.

kubectl exec <POD> -- sh -c 'for i in 1 2 3; do time wget -qO- http://localhost:8080/ready >/dev/null; done'
real    0m0.41s
real    0m3.10s
real    0m0.39s

The spikes line up with background work in the handler — a probe endpoint should be a cheap, constant-time check.

5. Dependency check inside the probe times out

The readiness handler synchronously calls a database or downstream service; when that dependency is slow, the probe inherits the latency and times out.

kubectl logs <POD> | grep -i -E 'ready|db|timeout' | tail -5
2026-06-23T14:31:02Z WARN readiness: db ping took 4200ms (threshold 500ms)
2026-06-23T14:31:07Z WARN readiness: db ping took 5000ms (timeout)

The probe is only as fast as the slowest dependency it checks; deep dependency checks belong in readiness, not liveness, and must be bounded.

6. Liveness probe too aggressive, causing a restart loop

A liveness probe with a tight timeout and low failureThreshold kills a pod that is merely slow, restarting it before it ever becomes healthy — a classic crash loop with no app crash.

kubectl get pod <POD> -o jsonpath='{.spec.containers[0].livenessProbe}{"\n"}' | jq .
{
  "httpGet": { "path": "/ready", "port": 8080 },
  "initialDelaySeconds": 5,
  "timeoutSeconds": 1,
  "periodSeconds": 3,
  "failureThreshold": 1
}

A 1s timeout, 3s period, and failureThreshold: 1 restarts the container on the first slow response. Loosen liveness and let readiness handle slowness.

Diagnostic Workflow

Step 1: Read the probe failure event

kubectl describe pod <POD> | sed -n '/Events:/,$p'

Confirm whether it is a Readiness or Liveness failure and that the reason is context deadline exceeded (a timeout) versus a non-2xx status code.

Step 2: Dump the probe spec

kubectl get pod <POD> -o jsonpath='{.spec.containers[0].readinessProbe}{"\n"}' | jq .
kubectl get pod <POD> -o jsonpath='{.spec.containers[0].livenessProbe}{"\n"}'  | jq .

Note path, port, initialDelaySeconds, timeoutSeconds, periodSeconds, and failureThreshold.

Step 3: Reproduce the probe by hand from inside the pod

kubectl exec <POD> -- sh -c 'time wget -qO- -S http://localhost:<PORT><PATH> 2>&1 | head -5'

Compare the measured response time against timeoutSeconds, and confirm the path/port actually answer.

Step 4: Correlate with app logs and load

kubectl logs <POD> --tail=50
kubectl top pod <POD>

Look for slow-startup messages, dependency latency, or CPU saturation lining up with the probe failures.

Step 5: Tune the probe and roll out

kubectl edit deployment <NAME>   # adjust delay/timeout/threshold or add startupProbe
kubectl rollout status deployment <NAME>
kubectl get pod <POD> -w

Example Root Cause Analysis

A Spring Boot service orders deploys but every pod stays 0/1 READY and restarts every couple of minutes. The events show both readiness and liveness timing out:

Warning  Unhealthy  kubelet  Readiness probe failed: Get "http://10.1.5.31:8080/actuator/health": context deadline exceeded
Warning  Unhealthy  kubelet  Liveness probe failed: Get "http://10.1.5.31:8080/actuator/health": context deadline exceeded
Normal   Killing    kubelet  Container app failed liveness probe, will be restarted

The probe spec is tight:

kubectl get pod orders-6f7c9d4b8-2lm5x -o jsonpath='{.spec.containers[0].livenessProbe}{"\n"}' | jq .
{
  "httpGet": { "path": "/actuator/health", "port": 8080 },
  "initialDelaySeconds": 10,
  "timeoutSeconds": 1,
  "periodSeconds": 5,
  "failureThreshold": 3
}

Hand-testing the endpoint from inside the pod once it is up:

kubectl exec orders-6f7c9d4b8-2lm5x -- sh -c 'time wget -qO- http://localhost:8080/actuator/health'
{"status":"UP"}
real    0m0.30s

It is fast once warm — but the JVM takes ~35s to start, far past the initialDelaySeconds: 10. The first liveness probes time out during startup, hit failureThreshold: 3, and the kubelet kills the container before it ever finishes booting — a restart loop with no application error.

Fix: add a startupProbe to cover the slow boot and relax the liveness timeout so transient slowness does not kill the pod:

kubectl patch deployment orders --type=merge -p '{
  "spec":{"template":{"spec":{"containers":[{"name":"app",
    "startupProbe":{"httpGet":{"path":"/actuator/health","port":8080},
      "failureThreshold":30,"periodSeconds":5},
    "livenessProbe":{"httpGet":{"path":"/actuator/health","port":8080},
      "timeoutSeconds":3,"periodSeconds":10,"failureThreshold":3}}]}}}}'
kubectl rollout status deployment orders

The startup probe now allows up to ~150s to boot; once it passes, liveness takes over with a sane 3s timeout, and the pods reach 1/1 READY without restarting.

Prevention Best Practices

  • Use a dedicated startupProbe for slow-booting apps so initialDelaySeconds on liveness/readiness does not have to absorb startup time.
  • Keep health endpoints cheap and constant-time; never run DB scans or downstream calls inline in a liveness probe.
  • Set timeoutSeconds generously relative to measured p99 latency, and size failureThreshold/periodSeconds so transient slowness does not trigger a restart.
  • Put dependency checks in readiness (which only removes the pod from endpoints), not liveness (which restarts it), so a slow database does not crash-loop your pods.
  • For triaging recurring probe and restart events, the free incident assistant can summarize the kubelet Unhealthy/Killing events into the likely probe misconfiguration.

Quick Command Reference

# See the probe failure event
kubectl describe pod <POD> | sed -n '/Events:/,$p'

# Dump the probe specs
kubectl get pod <POD> -o jsonpath='{.spec.containers[0].readinessProbe}{"\n"}' | jq .
kubectl get pod <POD> -o jsonpath='{.spec.containers[0].livenessProbe}{"\n"}'  | jq .

# Reproduce the probe from inside the pod
kubectl exec <POD> -- sh -c 'time wget -qO- -S http://localhost:<PORT><PATH> 2>&1 | head -5'

# Correlate with logs and resource use
kubectl logs <POD> --tail=50
kubectl top pod <POD>

# Tune and roll out (add startupProbe, relax timeoutSeconds/failureThreshold)
kubectl edit deployment <NAME>
kubectl rollout status deployment <NAME>
kubectl get pod <POD> -w

Conclusion

A Readiness probe failed: context deadline exceeded (or the liveness equivalent) means the container did not answer the kubelet’s health check within timeoutSeconds. The usual root causes:

  1. The app is slow to start and initialDelaySeconds/timeoutSeconds are too low.
  2. The health endpoint slows down under load and exceeds the deadline.
  3. The probe targets the wrong path or port.
  4. The probe hits a heavy or blocking handler instead of a cheap check.
  5. A dependency check inside the probe (DB, downstream service) times out.
  6. An over-aggressive liveness probe restarts a merely-slow pod in a loop.

Measure the real response time from inside the pod first, then add a startupProbe and right-size the timeouts — most probe timeouts are configuration, not a broken app.

Free download · 368-page PDF

Download the Free 500-Prompt DevOps AI Toolkit

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.