How to Fix a 400 Bad Request Error
Tell a cookie problem from a broken URL or body, then fix the part the server rejected.
Updated
TL;DR
400 Bad Request means the website's server could not or would not read your request, because something in it, such as a URL, header, cookie or body, was malformed. Sending it again unchanged fails the same way, so in a browser clear that site's cookies first.
What a 400 looks like in each server and client
Server pages often name the reason; clients print the code and little else, so read the body too.
| Where | What you see |
|---|---|
| nginx, one header line over its buffer | 400 Bad Request Request Header Or Cookie Too Large nginx |
| nginx, http:// sent to an HTTPS port | 400 Bad Request The plain HTTP request was sent to HTTPS port nginx |
| Apache httpd, Cookie over LimitRequestFieldSize | Bad Request Your browser sent a request that this server could not understand. Size of a request header field exceeds server limit. |
| Flask (Werkzeug 3.1 and earlier) | Bad Request The browser (or proxy) sent a request that this server could not understand. |
| Python requests (raise_for_status) | requests.exceptions.HTTPError: 400 Client Error: Bad Request for url: https://example.com/api/search |
| curl with --fail | curl: (22) The requested URL returned error: 400 |
| Python urllib | urllib.error.HTTPError: HTTP Error 400: Bad Request |
Why this happens
Your request broke the server's rules for size or format, so it stopped reading.
Browsers attach a site's cookies to every request, and RFC 6265 asks them to hold at least 50 cookies of 4,096 bytes per domain, far more than nginx or Apache accept in one header line by default.
Diagnose your 400 first
Each check rules out one suspect: cookies, the route, the body or server limits.
Open the page in an Incognito window; if it loads there, data your normal profile sends, such as that site's cookies, caused the 400.
Read the error page; text such as Request Header Or Cookie Too Large names the part of the request the server refused.
With curl -v through your proxy to an https:// URL, find the 400; under CONNECT, the proxy refused; after the proxy's 200, the site did.
Print the response body as well as the status; if it names a field or a JSON parse error, the server rejected your body.
If you run the site, lower its error log to info; AH00561 in Apache or too long header line in nginx means an oversized header.
Solutions ranked by effectiveness
Pick the card that matches where you saw the 400: your browser, your own code or your server.
- Most common fix
Delete the site's cookies in your browser
Applies to browser visitors. Removing one site's stored data may sign you out of that site, while every other site keeps its cookies.
In Chrome, open More > Settings > Privacy and security > Third-party cookies.
Select See all site data and permissions, then search for the site's name.
Select Delete next to the site, confirm, then reload the page.
- For developers
Encode the URL and match the body type
Applies when your code builds the request itself. Let an encoder build the query string and a serializer build the JSON, and label the body with a matching Content-Type.
import json, urllib.error, urllib.parse, urllib.request query = urllib.parse.urlencode({"q": "red shoes", "city": "São Paulo"}) url = "https://example.com/api/search?" + query body = json.dumps({"name": "Ana", "tags": ["new"]}).encode() req = urllib.request.Request(url, data=body, method="POST", headers={"Content-Type": "application/json"}) try: with urllib.request.urlopen(req, timeout=30) as res: print(res.status, res.read(300).decode()) except urllib.error.HTTPError as err: print(err.code, err.read(300).decode(errors="replace")) - Site owners
Size header buffers for your real cookies
Applies when your nginx or Apache logs oversized headers from ordinary visitors; raise the per-line limit.
nginx: set large_client_header_buffers 4 16k; in the http or server block.
Apache: raise LimitRequestFieldSize from 8190 in the server config or first virtual host.
Run nginx -t or apachectl configtest, then reload the server.
Stop the 400 from coming back
Habits for request code and for servers, so a malformed request is caught before it ships.
Let your HTTP library set Host and Content-Length; RFC 9112 makes servers reject two Host lines or a bad length.
Write https:// for every port that serves TLS, such as 443; nginx answers plain http:// there with 400.
Return a short reason in each 400 body, as RFC 9110 advises, so callers can fix their own request.
Keep session data on the server and only an ID in the cookie, so Cookie headers stay small.
Related errors
Learn more
FAQ
Proxy errors that name the field
Invalid Geonode username flags get a 403 with details about which field caused the issue.


