Skip to content
RU

upstream request timeout (Envoy, Istio): Why the Proxy Gave Up and Returned 504

What it means: The backend accepted the request but did not finish its response within Envoy's route timeout, so Envoy answered 504.

  1. Find which route timeout applied
  2. Measure the backend's real response time
  3. Fix the slow query or call
  4. Raise the timeout only where justified

Test your URL now

Requests the address and shows the status code and what the server sends back.

What "upstream request timeout" means

When the route's timer fires, Envoy's router aborts the upstream request with the response flag UT (UpstreamRequestTimeout) and, when the timeout response code is 504 Gateway Timeout (the normal case), sends the body upstream request timeout (router.cc). The response therefore looks like this:

HTTP/1.1 504 Gateway Timeout
server: envoy

upstream request timeout

The timer is the route timeout. Its documentation says: "If not specified, the default is 15s. This spans between the point at which the entire downstream request (i.e. end-of-stream) has been processed and when the upstream response has been completely processed", and "This timeout includes all retries" (route_components.proto). So a backend that streams a large response for more than 15 seconds can be cut off even though it started answering quickly.

This is not a connect problem: the connection worked. Failures to connect show up as upstream connect error with a 503.

Where the timeout comes from

SettingWhereEffect
Route timeoutEnvoy route configTotal budget for the request, including retries; 15 s when not set; 0 disables it
Retry per_try_timeoutRoute retry policyBudget for each attempt; if unset, each attempt can use the whole route timeout, so a timed-out request is not retried
x-envoy-upstream-rq-timeout-msRequest headerOverrides the route timeout per request when the proxy trusts the caller's Envoy headers
Istio VirtualService timeoutIstioIstio's request timeout is disabled by default, so in a mesh this error usually comes from an explicit timeout on the route
Gateway or ingress settingsEnvoy Gateway, Contour, API gatewaysProducts expose the same route timeout under their own names

The per-try note matters for diagnosis: with a 5xx retry policy and no per-try timeout, a request that times out is not retried, because the total budget is already spent (RetryPolicy.per_try_timeout). In Istio, the default request timeout is disabled (Istio request timeouts), so look for a timeout: line in the VirtualService first.

Typical causes

  • A genuinely slow endpoint. Reports, exports, search over unindexed columns, image processing in the request path.
  • A slow dependency. The backend waits on a database lock, a third-party API or DNS, then answers after the proxy has given up.
  • Long responses counted in full. Downloads and server-sent events count against the route timeout until the last byte; streaming routes need the timeout disabled or raised.
  • Retries eating the budget. Three attempts at five seconds each will not fit into a ten-second route timeout.
  • Overload. Requests queue in the backend's worker pool; latency grows with load, and timeouts appear only at peak.

A timeout in Envoy does not stop the work in your application. The backend may still finish the job after the client got a 504, so retried POSTs can run twice unless the endpoint is idempotent.

How to fix it

  1. Time the backend directly, bypassing the proxy:
    kubectl exec deploy/productpage -c istio-proxy -- curl -s -o /dev/null -w 'ttfb=%{time_starttransfer} total=%{time_total}\n' http://reviews:9080/report
    A total above the route timeout confirms the cause.
  2. Find the timeout in force. Dump the route: istioctl proxy-config route deploy/productpage -o json | grep -n '"timeout"', or read your Envoy route config. No value means 15 s in plain Envoy.
  3. Fix the slow part: add the missing index, move the export to a background job and return 202, cache the expensive call.
  4. Set timeouts deliberately. Raise the route timeout only for the routes that need it, and set per_try_timeout lower than the route timeout if you rely on retries.
  5. For streaming (downloads, SSE, long-polling) set the route timeout to 0 and rely on idle_timeout instead, which bounds silence rather than total duration.

How to confirm the fix

curl -s -o /dev/null -w '%{http_code} %{time_total}s\n' https://example.com/report
# 200 3.412s

The status must be 200 and the total time comfortably below the route timeout, not just under it: a response at 14.8 s against a 15 s limit will fail again under load. The access log should stop showing UT for the route. The HTTP status checker shows the status code and headers of your public URL from outside your network.

Related errors

60+ Status CodesComplete HTTP status code reference
Search by CodeQuick search for 200, 301, 404, 500
Categories 1xx–5xxInformational, success, redirects, errors
Examples & CausesWhen it occurs and how to fix it

Why teams trust us

60+
status codes
1xx-5xx
all categories
SEO
ranking impact
Free
online reference

How to use the reference

1

Enter code or keyword

2

Find description and causes

3

Apply recommendations

HTTP Status Codes Reference

HTTP status codes are three-digit numbers that the server returns for every request. They tell the browser and search crawlers what happened: success, redirect, or error.

Quick Search

Enter a code or keyword — instant result with description.

All Categories

1xx Informational, 2xx Success, 3xx Redirect, 4xx Client Error, 5xx Server Error.

Causes & Fixes

For each code: typical causes and concrete steps to resolve.

SEO Impact

How each code affects indexing and link juice transfer in Google.

Who uses this

Developers

choosing correct status

SEO

redirect optimization

DevOps

5xx error diagnostics

Marketers

landing page check

Common Mistakes

Confusing 301 and 302301 is permanent (passes SEO equity), 302 is temporary (does not).
Returning 200 on error"Soft 404s" — a 404 page with status 200 — confuse search engines and stay indexed.
Ignoring 5xx errors500, 503 are server failures. Prolonged episodes remove pages from the index.
Redirect chainsA→B→C instead of A→C slows loading and dilutes SEO equity. Simplify chains.

Best Practices

Use 301 for permanent redirectsThis passes 90–99% of link equity to the new URL.
Return 404 for missing pagesDon't mask 404 as 200 — it hurts SEO and UX.
Monitor 5xx in real timeSet up an HTTP monitor that alerts on 5xx.
Use 410 instead of 404410 Gone means "page permanently removed" — Google de-indexes faster.

Monitor HTTP statuses automatically

HTTP monitor alerts when response code changes or 5xx appears.

Sign up free

Learn more

Sources

Frequently Asked Questions

What is the default timeout in Envoy?

The route timeout defaults to 15 seconds when it is not set. It covers the time from the end of the client request to the end of the upstream response and includes all retries.

Does Istio have a default request timeout?

No. Istio disables the request timeout by default, so an upstream request timeout in a mesh usually comes from a timeout set in a VirtualService, a gateway or the application itself.

Why does a download stop after exactly 15 seconds?

The route timeout counts until the response has been completely processed, so a long download or stream hits it. Disable the route timeout for that route and use idle_timeout instead.

Will Envoy retry a request that timed out?

Only if a per_try_timeout is set below the route timeout. Without it, one attempt uses the whole budget and nothing is left for a retry.

Does the backend stop working when Envoy returns 504?

Not necessarily. The proxy stops waiting, but the application may still complete the request, so make retried writes idempotent.

Try the live tool that powered this guide

Free plan — 10 monitors, checks every 5 min, no card required. Upgrade for 1-minute interval and multi-region monitoring.