400 Bad Request (tested)
400 Bad Request means the server could not parse or accept the request itself. It is the generic "your request is broken" code. We sent broken requests to real servers and wrote down exactly what came back.
1. What a 400 means
The server got your request but refused it because something in it was malformed. It is a client-side error: retrying the same request gives the same 400. The fix is to change the request.
A 400 can come from two layers. The HTTP parser rejects bytes it cannot read, before your code runs. The framework rejects a body it cannot decode, such as broken JSON. Validation errors in your own code often use 422 Unprocessable Entity instead.
2. Parser-level 400s in Node.js 24 (measured)
We sent raw bytes to a plain http.createServer() on Node.js 24.21.0. For every broken request below, Node replied with exactly this and closed the connection. There is no body, and your request handler never runs.
HTTP/1.1 400 Bad Request
Connection: close
| What we sent | Node.js 24 result |
|---|---|
GARBAGE as the request line | 400, connection closed |
Header name with a space: Bad Header: v | 400, connection closed |
| Control byte (0x01) in a header value | 400, connection closed |
Space in the path: GET /a b HTTP/1.1 | 400, connection closed |
| DEL byte (0x7F) in the path | 400, connection closed |
Two different Content-Length headers (5 and 6) | 400, connection closed |
HTTP/1.1 with no Host header | 400 (with Date and an empty chunked body) |
HTTP/1.1, no Host, server option requireHostHeader: false | 200 OK |
HTTP/1.0 with no Host header | 200 OK |
So Node.js 24 does reject HTTP/1.1 requests without Host by default. You can turn that off with http.createServer({ requireHostHeader: false }), but real clients always send Host, so a missing one usually means a broken hand-written client.
Headers that are too large get a different code. See 431 Request Header Fields Too Large.
3. Malformed JSON in Express (measured)
With app.use(express.json()) on Express 5.2.1, we posted {"a":1,} (trailing comma) with Content-Type: application/json. The parser raised an error with status 400. Our error handler printed its fields:
HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8
{"type":"entity.parse.failed","message":"Expected double-quoted property name in JSON at position 7 (line 1 column 8)","status":400}
Check err.type === 'entity.parse.failed' in your error handler to return a clean message instead of a stack trace.
4. Malformed JSON in Flask (measured)
On Flask 3.1.3, reading request.json on the same broken body returned:
400 BAD REQUEST
<title>400 Bad Request</title>
<h1>Bad Request</h1>
<p>The browser (or proxy) sent a request that this server could not understand.</p>
The page does not say the JSON was the problem. Two more results from the same run:
- Valid JSON sent as
text/plaingave415 Unsupported Media Type, not 400: "Did not attempt to load JSON data because the request Content-Type was not 'application/json'." See 415 Unsupported Media Type. request.get_json(silent=True)on broken JSON returnedNoneand our route answered 200. Use it when you want to send your own error.
5. What clients do before the server sees anything (measured)
| Client and input | Result |
|---|---|
curl 8.14.1, URL http://localhost:8986/a b | Not sent. curl: (3) URL rejected: Malformed input to a URL function, exit code 3 |
curl, URL with %20 instead of the space | Sent, server saw /a%20b, 200 |
| curl, header value with a 0x01 byte | Sent as-is; Node replied 400 |
Node 24 fetch(), header value with a newline | TypeError: Headers.append: "a\nb" is an invalid header value. |
Node 24 fetch(), header name Bad Header | TypeError: Headers.append: "Bad Header" is an invalid header name. |
Node 24 fetch(), header value with ✓ | TypeError: Cannot convert argument to a ByteString because the character at index 5 has a value of 10003 which is greater than 255. |
Node 24 fetch(), URL with a space | Encoded to /a%20b and sent, 200 |
So curl and fetch() catch many mistakes on your side. Raw sockets, old libraries and hand-built requests do not, and the server answers 400.
6. 400s you see in the browser (from documentation, not measured)
- nginx "400 Bad Request – Request Header Or Cookie Too Large". The cookies for that site grew past nginx's header buffer. Clear cookies for the site. Full fix: Request Header Or Cookie Too Large.
- Google or YouTube "400. That's an error." Usually a bad or oversized cookie, or a broken URL. Clearing cookies for google.com or youtube.com, or trying a private window, is the usual fix.
- Broken URL encoding. A stray
%not followed by two hex digits, or unencoded spaces and quotes, can make a server reject the URL. Encode query values withencodeURIComponent()or your library's equivalent.
7. Quick fix checklist
- Browser: clear cookies for the site, then reload. Try a private window.
- Check the URL for spaces, stray
%signs or pasted junk. - API client: validate your JSON (a trailing comma is enough to fail) and send
Content-Type: application/json. - Check header names and values for spaces, newlines or non-ASCII characters.
- Hand-built HTTP/1.1 requests: always send
Hostand oneContent-Length.
Frequently asked questions
Is 400 Bad Request my fault or the server's?
Usually the request is the problem. The server could not parse it or decode its body. Retrying the same request will fail again; change the request.
Does Node.js return 400 when the Host header is missing?
Yes, in our test on Node.js 24.21.0 an HTTP/1.1 request with no Host got 400. HTTP/1.0 without Host got 200, and the server option requireHostHeader: false turns the check off.
Why does Flask return 400 for my JSON?
request.json raises a 400 when the body is not valid JSON. In our test the page only said 'The browser (or proxy) sent a request that this server could not understand.' Use request.get_json(silent=True) to handle it yourself.
What is entity.parse.failed in Express?
It is the error type express.json() sets when the body is not valid JSON. The error has status 400 and a message such as 'Expected double-quoted property name in JSON at position 7'.
How do I fix a 400 error in my browser?
Clear cookies for that site and reload, or try a private window. Also check the URL for spaces or stray % signs. Oversized cookies are a common cause on nginx sites.
Written with AI assistance. Measured on 2026-10-02 with Node.js 24.21.0 (http module), Express 5.2.1, Flask 3.1.3 / Werkzeug 3.1.9 and curl 8.14.1. Raw requests were sent with a Python socket so nothing fixed them on the way. The nginx, Google and cookie notes come from documentation, not our runs. PlainHeaders is our extension; curl, Node.js, Express and Flask are free.