499 Token Required or Client Closed Request
The 499 status code has two distinct meanings: ArcGIS uses 499 Token Required for missing Authentication tokens, and nginx logs 499 Client Closed Request when the client disconnects before receiving a response.
Usage specific to ArcGIS
The 499 Token Required code indicates the server expects an Authentication token with the HTTP request and received none. Resolving the error means resubmitting with a valid token.
As with the neighboring 498 code, ArcGIS deployments have been observed reporting the value inside the JSON error object of a 200 response rather than on the status line. A client branching on the HTTP status alone sees a success and proceeds with an error document.
The number collides with the nginx meaning described below, and the two behave in opposite ways. The ArcGIS code travels in a response body, while the nginx code never reaches a client at all.
Usage specific to nginx
The 499 Client Closed Request status code means the client closed the HTTP connection before the server finished processing. The final response never reaches the client. This code appears only in the nginx logs.
Common causes include client-side timeouts, users leaving the page, and load balancers closing idle connections.
Examples
ArcGIS Token Required
A client sends a request to an ArcGIS REST API endpoint without the required token. The server reports 499 Token Required in the response body while the observed HTTP status line carries 200 OK.
Request
GET /arcgis/rest/services/Map/MapServer?f=json HTTP/1.1
Host: www.example.re
Response
HTTP/1.1 200 OK
Content-Type: application/json
{
"error": {
"code": 499,
"message": "Token required.",
"details": []
}
}
The observed status line reports success. Only the
code
field inside the error object identifies the
failure.
nginx Client Closed Request
A client sends a long-running request but disconnects before the server responds. The nginx access log records the 499 status code.
Request
GET /api/heavy-report HTTP/1.1
Host: www.example.re
Response (nginx log entry only)
192.168.1.50 - - [02/Mar/2026:14:22:10 +0000] "GET /api/heavy-report HTTP/1.1" 499 0 "-" "python-requests/2.31.0"
No HTTP response is sent. The client disconnected before the server completed processing.
Diagnosing 499 in nginx
The code exists for logging alone. nginx never writes
the value to the wire, and error_page 499 is
rejected
outright, failing a configuration test with an
invalid value error. Among every code between 300 and
599, 499 is the only one the parser refuses, which
reflects the fact no client is left to receive a
response.
A rise in 499 usually points at upstream latency rather than at unreliable clients. The client gave up first, so the question is what caused the wait.
log_format latency '$remote_addr $status "$request" '
'rt=$request_time '
'uct=$upstream_connect_time '
'uht=$upstream_header_time '
'urt=$upstream_response_time';
Reading $request_time across the 499 rows separates
the causes. Values scattered at random reflect visitors
leaving before the response arrives. Values clustering at exactly 30 or
60 seconds point at a fixed timeout in a client
library, a load balancer, or a CDN in front of nginx,
and the number identifies which one.
The generating log line also sits at info level, and the default error log setting discards the entry.
error_log /var/log/nginx/error.log info;
The proxy_ignore_client_abort directive changes
what nginx does when the client disappears. The
default keeps the current behavior, closing the
upstream connection immediately and logging 499.
Turning the directive on holds the upstream request
open to completion and logs whatever the upstream
returned.
proxy_ignore_client_abort on;
Enabling the directive removes the code from the logs
without addressing the cause, and holds worker
connections and upstream capacity for work nobody
awaits. Reducing proxy_read_timeout, or making the
upstream answer faster, addresses the underlying
latency instead.
Other proxies record the same condition without a status code. HAProxy marks a client-side disconnect in its termination state field, and Envoy reports a zero status alongside a downstream termination flag. nginx is unusual in surfacing the condition as a pseudo-status, which is why dashboards grouping by status code show a bucket other stacks lack.
How to fix
nginx Client Closed Request
Identify slow upstream targets first. Add
$upstream_response_time and
$upstream_connect_time to the nginx log
format to measure backend latency:
log_format timed '$remote_addr $status '
'$upstream_response_time '
'$upstream_connect_time '
'$request_uri';
Enable proxy_ignore_client_abort for endpoints
where the backend operation must complete even
after the client disconnects. This prevents
nginx from terminating the upstream request
when the client drops the connection:
location /api/long-task {
proxy_ignore_client_abort on;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
Increase proxy timeouts to match the expected
backend processing time. The three relevant
directives are proxy_connect_timeout (time to
establish the upstream connection),
proxy_read_timeout (time between two successive
read operations from upstream), and
proxy_send_timeout (time between two successive
write operations to upstream).
Reduce backend response time. Slow database queries, unoptimized API endpoints, and resource contention on the upstream server are the root cause in most 499 cases. Profile and optimize the slow endpoints rather than increasing timeouts indefinitely.
Review the nginx access log for patterns. Filter for 499 entries and correlate by request URI, time of day, and response size to identify specific endpoints or traffic spikes triggering client disconnections.
For load balancer or CDN clients upstream of nginx, ensure the load balancer idle timeout exceeds the nginx proxy timeout. A load balancer closing the connection before nginx receives the upstream response produces 499.
ArcGIS Token Required
Include a valid Authentication token in the request. The ArcGIS server expects a token and rejects requests without one.
Generate a token using the generateToken REST
endpoint and attach the value as a query parameter
(?token=...) or in the
X-Esri-Authorization header:
X-Esri-Authorization: Bearer <token>
The X-Esri-Authorization header is preferred
over the query parameter. Query parameters appear
in server logs and intermediate proxy logs,
exposing the token.
Verify the secured service requires token-based Authentication. Services configured for anonymous access do not require a token. Check the service security settings in ArcGIS Server Manager or the ArcGIS Portal admin interface.
See also
- 498
- Google: HTTP status codes and network errors
- ArcGIS REST API: Generate Token
- Esri Technical Support for ArcGIS error 499
- HTTP status codes