Deploy Error Decoder

nginx 'upstream prematurely closed connection' — fix the 502

Quick answer: nginx returned a 502 because your app - the upstream - closed the connection before sending a full response. Usually the app crashed or timed out on that request, was killed mid-request (OOM or a restart), or its keepalive timeout is shorter than nginx expects. Check the app log at that timestamp, align the timeouts, and make sure the worker is not being killed.

Not your exact error? Paste it into the Deploy Error Decoder →

What the error looks like

It appears in the nginx error log and shows the client a 502:

upstream prematurely closed connection while reading response header
from upstream, client: 1.2.3.4, server: example.com,
request: "GET /api/report HTTP/1.1", upstream: "http://127.0.0.1:3000/api/report"

The upstream: field names the app and route. nginx connected fine, then the app closed the socket before finishing the response - so the real cause is in the app, not nginx.

Why it happens

The app crashed mid-request

An unhandled exception killed the worker while it was responding - check the app log for a trace.

Worker killed (OOM / restart)

An out-of-memory kill or a deploy/restart cut the connection while the request was in flight.

App timeout shorter than the request

The app gives up on a slow request before nginx does, closing the socket.

keepalive race

nginx reuses a connection the app just closed because the app keepAliveTimeout is lower than nginx expects.

Diagnose it in three steps

1

Read the app log at that timestamp

# match the 502 time to the app log - a stack trace, a slow query, or nothing
# (silent exit) all point at the app, not nginx.
2

Check for OOM kills and restarts

dmesg | grep -i "killed process"     # OOM killer
journalctl -u myapp --since "10 min ago"   # restarts
3

Time the slow endpoint

curl -w "%{time_total}\n" -o /dev/null -s https://example.com/api/report
# longer than the app or nginx timeout? that is your 502.
The real fix

Fix the crash, align the timeouts, set keepalive

If the app crashed, fix the exception and stop the worker dying mid-request. If the request is genuinely slow, raise the timeouts on both sides. And set the Node keepalive higher than nginx to avoid the reuse race.

# nginx: raise read timeout for a genuinely slow route
location /api/report {
    proxy_pass http://app;
    proxy_read_timeout 120s;   # default 60s
}
upstream app { server 127.0.0.1:3000; keepalive 32; }

// Node: keepalive must outlast nginx's, headers slightly higher again
server.keepAliveTimeout = 65000;   // 65s
server.headersTimeout   = 66000;   // 66s

If the cause is an OOM kill, give the process more memory or fix the leak - a worker that dies mid-response will keep producing 502s no matter how you tune nginx.

How Infraveil handles this

Catch the dying worker, see the request

A 502 from a crashing or OOM-killed worker is a supervision problem - you need to see which request killed it and recover fast. On your own servers, Infraveil supervises your services, restarts a worker that dies, health-checks before sending traffic, and surfaces the failing request with its context - so a premature-close 502 is caught and explained, with recovery approval-gated and recorded.

Workers that crash or OOM are restarted, on infra you control
The failing request and its context surfaced in one view
Health checks gate traffic; recovery approval-gated and recorded

Frequently asked questions

What does 'upstream prematurely closed connection' mean?

Your app closed the connection before sending nginx a complete response, so nginx returns a 502. The upstream crashed, timed out, or was killed mid-request - nginx is reporting the upstream went away.

Why do I get a 502 only on some requests?

It usually points to a specific slow or crashing endpoint, or intermittent OOM kills and restarts. Correlate the 502 timestamps with your app log to find the trace, timeout, or out-of-memory event.

How do I fix the Node keepAliveTimeout race?

Set server.keepAliveTimeout higher than nginx's keepalive, and headersTimeout slightly higher again. Otherwise nginx may reuse a connection the app just closed, causing intermittent 502s under load - a common pairing is 65s and 66s.

Is it nginx or my app?

Almost always the app. nginx is the messenger reporting that the upstream dropped the connection. Check the app's logs and resource usage for that request first; tune nginx timeouts only once you know whether it crashed or ran long.