HTTP status codes / 400
400 Bad Request — HTTP Status Code
400 Bad Request means the server will not process the request because it thinks the client sent something wrong, such as broken syntax, invalid framing or bad input. It is a generic client error, so the response body or the server log usually holds the real reason. For a monitor that only sends a plain GET, a 400 almost always points to the URL or the server's front door, not to the app being down.
What 400 means
RFC 9110 (Section 15.5.1) defines 400 Bad Request as the server refusing, or being unable, to process a request because of something it perceives as a client error. The RFC's examples are malformed syntax, invalid message framing and deceptive request routing.
The important word is "perceives." 400 is the catch-all client error: a server sends it when it knows the request is unacceptable but no more specific 4xx code fits. That makes it vague by design, so treat it as "read the response body and the logs" rather than as a diagnosis.
When you see it
Almost every layer of the stack can produce a 400:
- Web servers such as nginx and Apache reject requests they cannot parse, including invalid header lines, a missing or duplicated
Hostheader, and headers larger than their buffers. - TLS front ends produce it when plain HTTP arrives on an HTTPS port. nginx shows "The plain HTTP request was sent to HTTPS port."
- Applications and frameworks return it for unparseable bodies (an Express
express.json()parser answers 400 on invalid JSON), missing required parameters and failed input checks. - CDNs and API gateways return it when a request fails their own validation before it reaches your origin.
Common causes
- Oversized cookies or headers. A site that writes many cookies can push the
Cookieheader past the server's limit. In nginx that limit comes fromlarge_client_header_buffers. - Malformed JSON or form data. A trailing comma or an unescaped quote is enough.
- Wrong scheme on the wrong port, such as
http://example.com:443/. - Bad characters in the URL, such as raw spaces or invalid percent-encoding, for example
%zz. - Proxy mismatches. A load balancer forwarding a
Hostheader the backend does not recognize, or a proxy that manglesTransfer-Encoding, can cause the backend to reject everything. - App-level validation that reports every problem as 400, including missing query parameters.
How to fix it
Start with the response body. Many servers and APIs put the actual reason there, and your error log will name the rule that fired.
For header size problems in nginx, raise the buffer only as far as you need, and ask why the headers grew in the first place:
# http or server block
large_client_header_buffers 4 16k;
For JSON APIs, return a useful message with the 400 so clients can fix their requests:
app.use(express.json());
app.use((err, req, res, next) => {
if (err.type === "entity.parse.failed") {
return res.status(400).json({ error: "Request body is not valid JSON" });
}
next(err);
});
For scheme mismatches, make sure plain HTTP traffic goes to port 80 and is redirected to HTTPS, rather than reaching the TLS listener. For URLs, percent-encode spaces and special characters before sending them.
If users report 400 errors that go away after clearing site data, audit which cookies your app and third-party scripts set, and drop the ones you no longer need.
How to check it
Print the status code and the start of the body, which often contains the reason:
curl -sS -i https://example.com/api/items?limit=abc | head -n 20
To test whether a header size problem is the cause, send a deliberately large cookie and compare:
curl -sS -o /dev/null -w "%{http_code}\n" \
-H "Cookie: test=$(head -c 20000 /dev/zero | tr '\0' 'a')" \
https://example.com/
What it means for uptime monitoring
PingRobot's checker sends a plain GET with the user agent PingRobot/1.0 (+https://pingrobot.io/bot), follows redirects, and counts the final response as up only when its status is between 200 and 399. A 400 is therefore reported as down.
Because the check carries no body and no cookies, a 400 rarely comes from the things that trip up real users. The usual suspects are the monitored URL itself (a typo, a stray character, an API endpoint that requires query parameters the monitor does not send) or the front door (a proxy or TLS setup that rejects the request). If a URL that returned 200 yesterday starts returning 400 to every client after a deploy or a proxy change, that is a real outage. If it only fails for the monitor, fix the monitored URL or point the monitor at a page that needs no parameters, such as the home page or a health endpoint.
Related codes
- 401 Unauthorized when the problem is missing credentials
- 413 Content Too Large when the body is too big
- 414 URI Too Long when the URL is too long
- 415 Unsupported Media Type when the body format is wrong
- 422 Unprocessable Content for well-formed but invalid input
- 431 Request Header Fields Too Large, the specific code for oversized headers
Start monitoring free — 10 monitors, no credit card.
Frequently asked questions
Is a 400 error my fault or the website's fault?
The server is saying the request was at fault. That can still be the site's problem, for example when a stale cookie the site set itself is now too large, or when a proxy rewrites requests incorrectly.
Why does clearing cookies fix some 400 errors?
Servers cap the size of request headers. When a site keeps adding cookies, the Cookie header can grow past that cap and nginx answers with 400 Request Header Or Cookie Too Large until the cookies are removed.
Should an API return 400 or 422 for invalid input?
Both are used. A common convention is 400 when the body cannot be parsed at all, such as broken JSON, and 422 when it parses but fails validation rules. Pick one convention and document it.