HTTP 504 Gateway Timeout

Gateway Timeout

HTTP 504 is Gateway Timeout: a server acting as a gateway or proxy didn’t get a timely response from the server behind it (RFC 9110 section 15.6.5). Something in the chain gave up waiting. The upstream may still be working on the request, and may finish it.

Which timeout fired

Every layer has a default, and the 504 comes from the first one to run out:

nginx proxy_read_timeout              60s   between two reads from the upstream
AWS ALB idle timeout                  60s
CloudFront origin response timeout    30s
API Gateway REST integration          29s   "Endpoint request timed out"
ingress-nginx proxy-read-timeout      60s

nginx logs upstream timed out (110: Connection timed out) while reading response header from upstream. Raising one timeout helps only if every layer in front of it allows at least as long: nginx at 120 seconds behind an ALB at 60 still gets cut off at 60, and the ALB sends the 504.

504, 502 or 408

the upstream didn't answer in time         504 Gateway Timeout
the upstream answered badly or hung up     502 Bad Gateway
the client was too slow sending            408 Request Timeout

408 (RFC 9110 section 15.5.9) is a server giving up on a client that didn’t finish sending its request; 504 is a proxy giving up on a server. Go’s httputil.ReverseProxy blurs the line: its default error handler answers 502 for timeouts too. Search 5xx timeout in the tool below: it lists 504 and Cloudflare’s unofficial 524, and leaves 408 out because it’s a 4xx.

What the client should do

Don’t assume nothing happened. A POST that timed out at the gateway may have charged the card anyway. Retry idempotent requests with backoff; for the rest, send an idempotency key or check the result before trying again. If the work honestly takes minutes, stop raising timeouts: accept it with 202, return a status URL, and let the client poll.

504 isn’t heuristically cacheable, though CloudFront caches it for 10 seconds by default. Googlebot slows down when it sees 5xx errors, and pages that keep timing out drop out of the index.

In your stack

location /reports/ {
    proxy_pass http://reports:8080;
    proxy_connect_timeout 5s;
    proxy_read_timeout 120s;    # raise the load balancer's idle timeout above this too
}
metadata:
  annotations:
    nginx.ingress.kubernetes.io/proxy-read-timeout: "120"
proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
    var ne net.Error
    if errors.As(err, &ne) && ne.Timeout() {
        w.WriteHeader(http.StatusGatewayTimeout) // ReverseProxy would send 502
        return
    }
    w.WriteHeader(http.StatusBadGateway)
}

Try it in the HTTP Status Codes

504 Gateway Timeout

  1. 504Gateway Timeout5xx Server error

    A gateway waited for the server behind it and gave up waiting.

    When to use it

    A slow upstream behind a proxy that has a timeout of its own.

    Common mistakes

    Blaming the client, when 408 is the code for a client that was too slow, and setting the proxy’s timeout shorter than the work honestly needs.

    Not cacheable by defaultRFC 9110

Every code, by class

Codes marked unofficial come from one server’s own convention — nginx, Cloudflare, cPanel, Microsoft — and are not in the IANA registry.

Runs in your browser. Nothing you enter is sent anywhere.