Debug guide · you're seeing
upstream sent too big header while reading response header from upstreamupstream sent too big header502 Bad Gateway
nginx Upstream Sent Too Big Header: Fix the 502
Fix nginx upstream sent too big header: measure response headers, size proxy or FastCGI buffers, and shrink oversized Set-Cookie and redirect headers.
On this page
TL;DR: nginx ran out of room while reading the upstream response headers. Measure the failing response directly at the app, then increase
proxy_buffer_sizein the affectedproxy_passlocation; usefastcgi_buffer_sizefor PHP-FPM. Moreproxy_buffersalone will not fix it. Look for oversizedSet-Cookie,Locationand debug headers, especially on authentication routes.
What it means
The useful part of the nginx error log is:
upstream sent too big header while reading response header from upstream
nginx’s upstream parser logs this when the buffer is full and header parsing still needs more bytes. Its normal failure path returns 502 Bad Gateway, unless a retry succeeds or your configuration handles the error differently.
This is the opposite direction from Request Header Or Cookie Too Large. The app has already received the request. nginx is rejecting what the app sends back. Changing large_client_header_buffers or client_max_body_size addresses a different problem.
Measure the upstream response
Run this from somewhere that can reach the app directly, bypassing nginx. Replace http://upstream with the app’s address and the exact failing path:
curl -sD - -o /dev/null http://upstream | wc -c
# Example route on a local HTTP upstream:
curl -sS --http1.1 -D upstream.headers -o /dev/null \
-H 'Host: example.com' 'http://127.0.0.1:3000/login'
wc -c < upstream.headers
-D dumps response headers; -o /dev/null discards the body. The count includes the status line and terminating blank line for this HTTP/1.1 response. Inspect curl’s errors too: zero bytes from a failed connection is not evidence of a small response.
Reproduce the method, Host, authentication and cookies of the failing request. An anonymous request may miss the session headers that trigger the 502. Do not substitute -I unless the failing request was HEAD, and do not add -L to this measurement: following redirects combines several response header blocks. Interim responses can also create extra blocks; inspect upstream.headers before treating its total as one response.
To rank the header lines by byte length without printing cookie or token values:
node -e 'const fs=require("node:fs"); const lines=fs.readFileSync("upstream.headers"); console.log(lines.toString("latin1").split("\r\n").filter(x=>x.includes(":")).map(x=>[Buffer.byteLength(x,"latin1")+2,x.slice(0,x.indexOf(":"))]).sort((a,b)=>b[0]-a[0]))'
Treat the captured file as sensitive. Measure each relevant response separately: the redirect into the identity provider, the callback, and the first request that creates or refreshes the session.
Find the growing header
- Session cookies. A serialized session or token can produce a large
Set-Cookie, and several cookies add to the same response header block. MDN describes each cookie as a separate Set-Cookie field. Splitting one session into more cookies does not reduce the total nginx must parse. - Authentication and OIDC redirects. Inspect both
LocationandSet-Cookieon the failing response. A long redirect URL contributes its whole header line to the buffer. OAuth2 Proxy documents multipart session cookies and recommends Redis for consistently large sessions, so only a small session ticket is stored in the browser. - Debug headers. Check any field containing serialized traces, query details or application state. Remove that payload from response headers and put diagnostic detail in server logs instead.
These are fields to measure, not a diagnosis from the status code. Use the byte counts to identify which one exceeds your route’s allowance.
Set the buffers for the upstream protocol
The nginx proxy module documents these defaults. The 4k or 8k choice depends on the platform’s memory page size:
| Directive | Default | Role |
|---|---|---|
proxy_buffer_size | 4k or 8k | Initial response buffer, including headers |
proxy_buffers | 8 4k or 8 8k | Response data buffers for one connection |
proxy_busy_buffers_size | 8k or 16k | Cap on buffers busy sending while the upstream response is still being read |
For proxy_pass, this illustrative configuration gives the header buffer 16 KiB. Choose a size above your measured header block, with room for normal variation:
location / {
proxy_pass http://127.0.0.1:3000;
proxy_buffer_size 16k;
proxy_buffers 8 16k;
proxy_busy_buffers_size 32k;
}
proxy_buffer_size is the line that fixes header capacity; the other two keep the buffer sizes compatible with it. nginx checks their relationship during configuration loading: the busy-buffer limit must be at least the larger of the header buffer and one body buffer, and fit within the body-buffer capacity minus one buffer. Run nginx -t before reloading.
proxy_buffering off still uses proxy_buffer_size to receive upstream data. It does not remove the header-size constraint. Likewise, hiding a header downstream does not remove nginx’s need to parse the upstream response first.
FastCGI and uwsgi
Change the directives matching the *_pass in the failing location. Put these illustrative settings alongside your existing upstream address and parameters:
# In a location using fastcgi_pass, such as PHP-FPM:
fastcgi_buffer_size 16k;
fastcgi_buffers 8 16k;
fastcgi_busy_buffers_size 32k;
# In a location using uwsgi_pass:
uwsgi_buffer_size 16k;
uwsgi_buffers 8 16k;
uwsgi_busy_buffers_size 32k;
The FastCGI and uwsgi modules each default to a 4k or 8k initial buffer, eight body buffers of that size, and an 8k or 16k busy-buffer limit. Changing proxy_buffer_size cannot enlarge a FastCGI or uwsgi response buffer.
gRPC
For grpc_pass, the relevant directive is grpc_buffer_size, also one memory page (4k or 8k) by default. The module passes responses synchronously and does not provide the grpc_buffers and grpc_busy_buffers_size pair:
# In the existing grpc_pass location:
grpc_buffer_size 16k;
Existing ingress-nginx deployments
The community ingress-nginx controller documents a 4k default and this annotation. Add it to the existing Ingress metadata:
metadata:
annotations:
nginx.ingress.kubernetes.io/proxy-buffer-size: "16k"
The same docs expose nginx.ingress.kubernetes.io/proxy-buffers-number and nginx.ingress.kubernetes.io/proxy-busy-buffers-size. Inspect the generated nginx configuration and controller logs after a change; do not assume that an accepted Kubernetes object proves nginx loaded it successfully.
As of this page’s review date, the project README says maintenance ended after March 2026, with no further bug fixes or security updates. Use this setting to repair an existing deployment while planning migration; the project explicitly advises against new deployments. These annotations belong to community ingress-nginx, not every controller with nginx in its name.
Raise the buffer, then stop the growth
A measured increase for a legitimate app response is a reasonable repair. Request-header limits govern bytes clients can submit; this response buffer governs what your upstream sends. The distinction does not make memory free: larger buffers across concurrent responses increase the capacity you must budget. Scope the change to the affected location rather than raising every route by habit.
Keep the response small anyway. Move session state out of cookies, stop reissuing redundant cookies, shorten redirect state where your authentication design allows it, and remove verbose diagnostic headers. A larger nginx buffer cannot guarantee that every downstream intermediary or browser will accept the response.
Reproduce and verify
nginx -t && nginx -s reload
nginx -T 2>&1 | grep -E 'proxy_buffer_size|fastcgi_buffer_size|uwsgi_buffer_size|grpc_buffer_size'
curl -sS -D - -o /dev/null 'https://example.com/failing-path'
Replay the same authenticated request through nginx and directly to the upstream. Success means the expected application response arrives, all intended cookies survive, and the matching error-log line stops appearing for that request. Check the login callback and session-refresh path as well as the first page load; otherwise you may have tested the smaller response.
Related
- nginx 502 Bad Gateway: other upstream errors that produce the same status.
- Request Header Or Cookie Too Large: limits on headers sent in the other direction.
- Set-Cookie: the response fields that create and update browser cookies.
Frequently asked questions
What does upstream sent too big header mean in nginx?
nginx filled its upstream header buffer before it could finish parsing the response headers. With no successful retry or custom error handling, the client receives 502 Bad Gateway. Measure the upstream response for the failing route and user.
Does proxy_buffers increase the response header limit?
No. For an HTTP proxy, proxy_buffer_size controls the initial response buffer. proxy_buffers holds response data after header parsing, and proxy_busy_buffers_size controls how much buffered data can be busy sending to the client.
What is the default proxy_buffer_size?
nginx defaults to one memory page, either 4k or 8k depending on the platform. The ingress-nginx controller documentation specifies its own 4k default. Check the configuration actually loaded on your server.
Does large_client_header_buffers fix this 502?
No. It controls headers arriving from the client. This error concerns headers coming back from the upstream application, so use the response-buffer directive for proxy_pass, fastcgi_pass, uwsgi_pass or grpc_pass.
Is raising the response header buffer a reasonable fix?
Yes, when a measured legitimate response needs more room. Apply the change to the affected route and account for memory under concurrency. Also remove unnecessary cookies, session state and debug headers so the response stops growing.
Sources
- nginx: proxy_buffer_size, proxy_buffers and proxy_busy_buffers_sizenginx.org
- nginx: FastCGI response buffersnginx.org
- nginx: uwsgi response buffersnginx.org
- nginx: gRPC response buffernginx.org
- nginx source: upstream header parsing and 502 handlinggithub.com
- nginx source: proxy buffer configuration constraintsgithub.com
- ingress-nginx: proxy buffer size annotationskubernetes.github.io
- ingress-nginx README: retirement and maintenance statusgithub.com
- OAuth2 Proxy: nginx integration and large session cookiesoauth2-proxy.github.io
- curl manual: --dump-header and --outputcurl.se
- MDN: Set-Cookiedeveloper.mozilla.org
- RFC 9110 Section 15.6.3: 502 Bad Gatewayrfc-editor.org
Related
Request Header Or Cookie Too Large: Fix 400 and 431
Fix 400 Request Header Or Cookie Too Large and 431 errors: find the oversized cookie or token, then check nginx, Apache, Node, ALB and Cloudflare limits.
nginx 502 Bad Gateway: Causes and Fixes by Error Log
Fix nginx 502 Bad Gateway by matching the error log: connection refused, prematurely closed connection, php-fpm socket permissions, too big header, keepalive.
Set-Cookie Header: Attributes, Examples and Browser Rules
Set-Cookie syntax and every attribute: Expires, Max-Age, Domain, Path, Secure, HttpOnly, SameSite, Partitioned, __Host- prefixes, with Express and Django.
ERR_EMPTY_RESPONSE: Find Who Closed the Connection
Debug ERR_EMPTY_RESPONSE and curl empty replies by checking app crashes, wrong ports, nginx 444, Docker listeners, keep-alive races and request framing.