499 Client Closed Request (nginx)
499 is not a real HTTP status. nginx writes it to its access log when the client closes the connection before nginx has sent a response. The client never receives a 499; it gave up first.
The client disconnected before nginx could send the response.
nginx records 499 in its access log; the client never receives it because it is already gone. It usually means the upstream was slow and the user, a browser navigation, or a client-side timeout gave up first. A rise in 499s is a latency signal: look at upstream response times.
Explained
Something on the client side ended the request: a user closed the tab or clicked away, a browser cancelled a superseded fetch, a mobile app or SDK hit its own timeout, or a load balancer in front of nginx timed out and dropped the connection.
The usual root cause is latency. If the upstream takes 30 seconds and the client's timeout is 25, every slow request shows up as a 499. Logging $request_time and $upstream_response_time in nginx's log_format shows how long those requests had been running.
By default nginx also aborts the upstream request when the client goes away. proxy_ignore_client_abort on; keeps the upstream request running, which helps when the upstream work must complete, at the cost of doing work nobody will see.
How to debug it
- Add
$request_timeand$upstream_response_timeto the nginx log format and see how long 499 requests ran before the client left. - Compare that duration with the client's timeout and with any load balancer or CDN idle timeout in front of nginx.
- Find the slow requests in the upstream logs and profile them.
- If 499s cluster on one endpoint, check whether the frontend cancels and reissues requests (for example on each keystroke in a search box); those are harmless.
Gotchas
- A health checker with a short timeout can generate steady 499s against a slow health endpoint.
- 499s do not appear in client-side error reports with that number; the client sees a timeout or abort error.
- Treat a sudden rise in 499s as a latency alert, not a client problem.
Related explainers
- 504 Gateway TimeoutA 504 means a proxy waited too long for the app behind it. Which timeout fired (nginx proxy_read_timeout,...
- 502 Bad GatewayA 502 means a proxy got no valid reply from the app behind it. How to read nginx's error log, common...
- 503 Service Unavailable503 means the server is temporarily unable to handle requests. Common sources: no healthy backends, nginx...