502 Bad Gateway from the load balancer. The cause is almost always a keep-alive timeout mismatch between your app and the ALB.
Why this happens
HTTP/1.1 connections stay open between requests so the ALB can reuse the same TCP socket to your task. Both ends have an idle timeout. If your app closes an idle connection before the ALB does, the ALB may already have sent the next request down that socket. The app resets the connection and the ALB returns a 502 to the client. The ALB idle timeout is 60 seconds by default. Framework defaults vary, and several are below that:
Anything lower than the ALB idle timeout can produce 502s.
The fix
Set the app’s keep-alive timeout higher than the load balancer’s idle timeout, so the ALB always closes idle connections first. With the default 60 s ALB timeout, use 65 s or more.- Next.js
- Node.js (Express, custom server)
- Fastify
- Rails (Puma)
- Django (Gunicorn)
- FastAPI (Uvicorn)
package.json
Infrastructure settings
If you would rather change the ALB than every app, lower its idle timeout instead — the rule is only that the ALB timeout is the smaller of the two. The relevant inputs:
Dropping
target_group_deregistration_delay to around 60 s does not affect 502s from keep-alive, but it lets rolling deploys finish faster without holding old tasks for five minutes. Set it to something longer than your slowest request.
502s only during deploys
If the 502s line up with deployments rather than appearing at random, the cause is different: tasks are being stopped while they still hold open connections. Make sure your server handlesSIGTERM by finishing in-flight requests and closing idle keep-alive connections before exiting. Node’s server.close() and Puma’s default behavior both do this.