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
Runningbut0/1 READYand never enters Service endpoints. - Events show
Readiness probe failed: ... context deadline exceeded. - Liveness failures show
Killingand 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
startupProbefor slow-booting apps soinitialDelaySecondson 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
timeoutSecondsgenerously relative to measured p99 latency, and sizefailureThreshold/periodSecondsso 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/Killingevents 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:
- The app is slow to start and
initialDelaySeconds/timeoutSecondsare too low. - The health endpoint slows down under load and exceeds the deadline.
- The probe targets the wrong path or port.
- The probe hits a heavy or blocking handler instead of a cheap check.
- A dependency check inside the probe (DB, downstream service) times out.
- 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.
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.