502 Bad Gateway
Server Error
The server, while acting as a gateway or proxy, received an invalid response from an upstream server. 502 means the gateway reached the upstream and got back something unusable. A malformed response, an early TCP close, an invalid HTTP framing, or in some implementations a connection refused. The fix is almost always on the upstream side, not the gateway side. Common gateway layers that emit 502 include Nginx, HAProxy, Cloudflare, AWS ALB, and Kubernetes ingress controllers.
When does this happen?
502 surfaces when a reverse proxy fronts your application and the application fails to deliver a coherent response. The application may have crashed mid-request, exited before flushing its body, returned a response that violates HTTP grammar, or simply refused the connection. Cloudflare's 502 page is a common public-facing example. When origin servers fail, Cloudflare returns 502 with a branded error page. Browsers show whatever HTML the proxy returns, so 502 pages are visible to end users and to crawlers, which treat them as transient. Persistent 502s on indexed pages cause de-indexing similarly to persistent 500s. The right place to debug 502 is the upstream's logs and health checks, not the proxy. Watch for connection-refused 502s after a container restart. The proxy's health checks may have lagged behind the actual readiness state of the upstream.
Common causes
- Backend application crashed mid-request and dropped the connection without sending a complete response.
- Backend is not running. Process died and the gateway's health check has not yet marked it down.
- Network issue between proxy and backend. Typically a misrouted internal DNS entry or a security-group misconfiguration.
- Backend returned malformed HTTP. Invalid headers, unterminated chunked encoding, missing status line.
- Backend's TLS certificate is expired or invalid and the proxy refuses to forward the response.
- Backend is behind a Kubernetes service whose pods are not ready, and the gateway is routing to an empty endpoint set.
- Buffer-size mismatch. The proxy's response buffer is smaller than what the backend sent, causing a read failure.
- DNS resolution failure for the upstream hostname.
- MTU mismatch in cross-region traffic causing packet drops on responses.
How to fix it
- Check whether the backend application is running. Process up, port listening, container healthy.
- Review the backend's logs for the time window of the 502. There is usually a crash, OOM kill, or exit message.
- Verify network connectivity between proxy and backend with curl or tcpdump from the proxy host.
- Confirm the backend's health endpoint returns 200 from the proxy's perspective. Health checks that pass from elsewhere but fail from the proxy point at a network issue.
- Increase the proxy's response timeout if the backend is slow but eventually replies. Nginx's proxy_read_timeout often needs tuning.
- Audit Kubernetes readiness probes. A too-strict probe can flap pods in and out and produce 502s during rollouts.
- Check the upstream's TLS certificate expiry. Proxies often return 502 on cert validation failures.
- Validate the upstream's HTTP output with curl directly against the backend. If it returns malformed output, the proxy will reject it.
Real-world examples
- Node application crashes due to an unhandled rejection and the container exits while a request is in flight.
- Reverse proxy notices the closed connection and returns 502 to the client. Container orchestrator restarts the pod and traffic recovers within seconds.
- Backend pod is rolling out and Kubernetes routes traffic to a pod that has not finished startup.
- Pod refuses the connection. Nginx ingress returns 502 until the readiness probe passes for the new pod.
- Cloudflare cannot reach the origin because the origin's IP changed and DNS has not updated.
- Cloudflare returns its 502 branded error page. Operator updates the DNS record and traffic recovers.
- Origin server's TLS certificate expired at midnight.
- CDN refuses to forward the request and returns 502. Operator renews the cert and the CDN starts forwarding again.
- Application sends a chunked response but encounters an OOM mid-stream and dies.
- Proxy reads a partial chunk, fails to parse, returns 502 to the client. Operator increases memory limits and the application stops dying.
- AWS ALB cannot reach EC2 instances because a security group change removed the listener rule.
- ALB returns 502. Operator reverts the security group and connectivity restores.
Debugging
- Check Nginx error logs (or your gateway equivalent) for the upstream error message. Usually "upstream prematurely closed connection" or "connection refused."
- Run curl --resolve api.example.com:443:<origin-ip> https://api.example.com/path directly against the origin to confirm whether the origin itself responds.
- Inspect backend application logs for crashes, OOMs, or panic messages in the same time window.
- Check container orchestrator events (kubectl get events, docker logs) for restart loops, OOM kills, or readiness probe failures.
- Verify TLS certificate expiry with openssl s_client -connect origin:443 -showcerts.
- Use tcpdump on the proxy host to confirm the connection to the backend is actually completing the TCP handshake.
How it differs from related codes
HTTP 500
500 means the application itself returned an error response. 502 means the gateway could not get a response at all. The application may be entirely down.
HTTP 503
503 is the upstream saying "I am temporarily unavailable" via a real HTTP response. 502 is the gateway saying "I did not get a response I could use." 503 is more polite; 502 implies the upstream is broken.
HTTP 504
504 is a gateway timeout. The upstream took too long to respond. 502 is a gateway error. The upstream responded but the response was unusable, or the connection failed entirely.
Related status codes
See HTTP 502 in your redirect chains?