Migrate to RunxBuild and earn up to $50 in hosting credit on your first deposit.

Calculate your savings
unxBuild
Back to Blog Troubleshooting

Error 431: Request Header Fields Too Large, and Why It Is Usually Cookies

Sean

Platform Writer

Sep 02, 2026
8 min read

A 431 means the server refused to process your request because the headers were too big before it even looked at what you were asking for — and in the overwhelming majority of cases the oversized header is Cookie, accumulated over months of a domain quietly collecting them.

Error 431: Request Header Fields Too Large, and Why It Is Usually Cookies

The tell is distinctive and worth recognising: the site works fine in a private window and fails in your normal browser. That single observation nearly always identifies the cause, because a private window has no cookies. Here is what is happening, how to fix it now, and how to stop it recurring — which is a different fix from clearing your cookies.

Table of contents

What the limit is and why it exists

Servers cap the size of request headers because they have to buffer them before parsing, and an unbounded header is a trivially cheap way to exhaust memory. The cap is a denial-of-service protection, not an arbitrary restriction.

The limits are lower than most people assume, and they vary by server. Node’s HTTP parser has historically defaulted to around 8KB for the whole header block and has moved between versions. Nginx defaults to a 4KB or 8KB buffer with a small number of larger buffers available. Apache’s limit is larger by default. Cloud load balancers and CDNs impose their own, sometimes lower than the origin’s.

The consequence of the variation is a genuinely confusing failure pattern: the same request works against one component of your stack and fails against another. A request that passes the CDN and fails at the origin, or passes in development and fails behind the production load balancer, is the normal shape of this bug.

The spec says the server should indicate in the response body whether the problem is the total size or a single field, and ideally name the offending header. Very few servers do. You will usually be diagnosing it yourself.

Confirming it is cookies, in thirty seconds

The diagnostic sequence is short and definitive.

  1. Open the site in a private window. If it works there and not in your normal session, it is cookies. This one test settles it most of the time.
  2. Count the bytes. In the browser console, document.cookie.length gives you the size of the cookies scripts can read. Note that this excludes HttpOnly cookies, so the real total sent to the server is larger — sometimes much larger.
  3. Look at the actual request. In the network tab, inspect the request headers on the failing request and look at the size of the Cookie header specifically. This is the ground truth.
  4. Check for a single oversized header. If cookies are modest, look for a large Authorization header — a JWT stuffed with claims, or a Kerberos/NTLM token, both of which get big — or a long Referer from a URL carrying many parameters.

The reason it accumulates unnoticed is that cookies from every subdomain that set them on the parent domain are sent on every request to every subdomain. Analytics, A/B testing, session state, feature flags, consent records, third-party embeds — each adds a little, none removes anything, and there is no cleanup process anywhere in the design.

Immediate fixes versus real fixes

There is a fix that stops the pain and a fix that stops the recurrence, and they are not the same.

Immediate: clear cookies for the domain. The site works again. This is what every support article recommends and it is genuinely the right first step for an affected user.

Also immediate, and a trap: raise the server limit. Node accepts --max-http-header-size, nginx has large_client_header_buffers, and most servers have an equivalent. Raising it works and it is the wrong permanent answer, because the cookies will keep growing and you will be back with a larger number. It also raises your memory exposure on a limit that exists for a reason.

Raise the limit as a temporary measure to stop users being locked out while you do the real fix. Do not treat it as the fix.

The real fix is to send fewer cookie bytes, and there are four ways to do that, in order of how much they help.

Sending fewer bytes, permanently

  1. Audit and delete. List every cookie the domain sets and find the owner of each. There will be cookies from a tool you stopped using two years ago that nobody removed, because nothing ever prompts anyone to. Delete those server-side by setting them with an expiry in the past.
  2. Scope by path and subdomain. A cookie set on the parent domain is sent to every subdomain forever. Set cookies on the specific host that needs them, and use Path so an admin-only cookie is not sent with every image request.
  3. Serve static assets from a cookieless origin. A separate hostname that never sets cookies means images, scripts and stylesheets carry no Cookie header at all. This is both a 431 fix and a genuine performance improvement, since you stop sending kilobytes of cookies with every asset request.
  4. Store an identifier, not the data. The most common cause of a genuinely enormous cookie is putting session state into it — user profile, permissions, preferences, cart contents. Store a short opaque session identifier and keep the state server-side in a database or cache. The cookie goes from kilobytes to tens of bytes.

Number four is the structural fix and it eliminates the problem rather than deferring it. Cookie-based session storage is appealing because it avoids server-side state, and it fails exactly like this once the state grows.

If you use a JWT as a session cookie, keep the claims minimal. A token carrying a full permission set and user profile is a large token sent on every single request, including requests for images.

Preventing it, and handling it gracefully

Two things worth building in, because a 431 is a hard failure for the user and they have no way to know what to do about it.

Monitor header size. Log the total request header size on a sample of requests and alert when the 95th percentile crosses a fraction of your limit. This turns a sudden outage into a gradual warning, and it is a handful of lines of middleware. Also make sure your limits are consistent across the CDN, load balancer and origin — the lowest one governs, and it is worth knowing which that is.

Handle it usefully when it happens. The default 431 is a blank error page, and a user with an oversized cookie jar cannot fix that. A custom handler can do better:

  • Return a small page that explains the problem in plain language.
  • Include a button that clears the site’s cookies and reloads.
  • Send Clear-Site-Data: "cookies" in the response, which instructs the browser to clear them directly.

The tricky part is that your error page is itself served over a request carrying the same oversized headers, so it has to be served by something with a higher limit — typically the edge or load balancer rather than the application. Worth testing rather than assuming.

Finally, add a cookie review to whatever periodic maintenance you already do. Cookies accumulate the way unused dependencies do: nobody adds one carelessly, and nobody removes one at all.

How this fits the rest of the stack

Serving assets from a cookieless origin fixes this and reduces transfer at the same time, since every asset request stops carrying kilobytes of cookies — which is a bandwidth line as well as a latency one. The RunxBuild hosting calculator shows bandwidth alongside the service and database so that trade is visible. On RunxBuild, a static site is a separate deployment from the service, which makes the cookieless-asset-origin split a deployment decision rather than a server configuration exercise.

Useful related references:

FAQ

What causes HTTP error 431?

Request headers exceeding the server’s size limit, and in most cases that means accumulated cookies. A domain collects cookies from analytics, A/B testing, session state, feature flags and third-party embeds over months, and nothing ever removes them. Less commonly it is one oversized header such as a large JWT in Authorization.

Why does the site work in incognito but not normally?

A private window starts with no cookies, so the Cookie header is small. Your normal session carries every cookie the domain has accumulated. That difference is the fastest confirmation that a 431 is cookie-related.

Should I just increase the header size limit?

Only as a temporary measure to stop users being locked out. The limit exists to bound memory use per connection, and raising it does not stop cookies growing — you will hit the larger limit later. Fix it by sending fewer bytes: delete unused cookies, scope them properly, and store a session identifier rather than session data.

How do I check how big my cookies are?

document.cookie.length in the console gives the size of script-readable cookies, but excludes HttpOnly ones so the real total is larger. The reliable measure is inspecting the Cookie header on the failing request in the network tab.

How can I show a useful page instead of a blank 431?

Serve a custom handler that explains the problem, offers a button to clear the site’s cookies, and sends Clear-Site-Data: cookies. It has to be served by a component with a higher header limit than the one that rejected the request — usually the edge or load balancer rather than the application.

#error 431#HTTP headers#cookies#Node.js#nginx