HTTP 502 Bad Gateway

Bad Gateway

HTTP 502 is Bad Gateway: a server acting as a gateway or proxy got an invalid response from the server behind it (RFC 9110 section 15.6.3). In practice “invalid” includes no response at all: a refused connection, a connection closed mid-request, bytes that aren’t HTTP. The proxy is working; the thing behind it isn’t.

Where to look

The proxy that sent the 502 logs why. In nginx’s error log:

connect() failed (111: Connection refused) while connecting to upstream
upstream prematurely closed connection while reading response header from upstream
upstream sent too big header while reading response header from upstream
connect() to unix:/run/php/php-fpm.sock failed (2: No such file or directory)

In order: nothing listens on that port; the app crashed or was killed mid-request; its response headers, often big cookies, overflowed proxy_buffer_size; PHP-FPM isn’t running. A Gunicorn worker killed by its own timeout, 30 seconds by default, shows up as the second line.

In the cloud

  • AWS ALB: the target closed the connection or sent a malformed response. The classic cause is keep-alive: Node’s server.keepAliveTimeout defaults to 5 seconds and the ALB’s idle timeout to 60, so the ALB reuses a connection the app has just closed. Make the app’s keep-alive timeout longer than the load balancer’s.
  • CloudFront: it couldn’t complete the TLS handshake with the origin, often because the origin’s certificate doesn’t cover the origin domain name, or the origin’s response was invalid.
  • Kubernetes ingress-nginx: pods stopped during a rollout before they left the Service’s endpoints, or a Service whose targetPort doesn’t match the port the container listens on. A short preStop sleep lets traffic drain before the process exits.
  • Go’s httputil.ReverseProxy answers 502 for any upstream error, timeouts included, unless you set its ErrorHandler.

502, 503 or 504

the upstream answered badly, or hung up           502 Bad Gateway
temporarily unable to serve: overload, no pods    503 Service Unavailable
the upstream didn't answer in time                504 Gateway Timeout

Your application shouldn’t send 502 for its own bugs; that’s 500. The code is for proxies, and for services that pass on a failure from the service behind them.

What the client should do

Retry idempotent requests with backoff; a 502 during a deploy usually clears within seconds. For a POST, check whether the work happened before sending it again. 502 isn’t heuristically cacheable, though CloudFront caches it for 10 seconds by default. Googlebot slows down on 5xx errors, and pages that keep failing drop out of the index.

In your stack

location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_buffer_size 16k;                # room for large response headers
    proxy_next_upstream error timeout;    # the default: on a failed connection, try the next server
}
const server = app.listen(3000);
server.keepAliveTimeout = 65_000;   // longer than the ALB's 60-second idle timeout
server.headersTimeout = 66_000;     // and this a little longer still
lifecycle:
  preStop:
    exec:
      command: ["sleep", "5"]

Try it in the HTTP Status Codes

502 Bad Gateway

  1. 502Bad Gateway5xx Server error

    A gateway or proxy got an unusable answer from the server behind it.

    When to use it

    A reverse proxy whose upstream crashed, closed the connection early, or sent something that was not a response.

    Common mistakes

    Reporting it for faults in your own application, and retrying forever when the upstream is simply down.

    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.