DEVESSENTIALS

HTTP 400 Bad Request

400 is the generic "your request is broken" response. RFC 9110's examples are malformed syntax, invalid message framing and deceptive request routing. Sending the same request again won't help: something in it has to change.

4xx · Client errorRFC 9110 §15.5.1

400 Bad Request

The server can't or won't process the request because of something it considers a client error.

Who fixes it: Client. Something in the request must change. But check the server's logs: limits set too low and over-strict parsers also produce 400s.

What 400 means

Because it's generic, a 400 is only as useful as its body. Good APIs say what was wrong ("body is not valid JSON at position 42", "missing query parameter: from"). Web servers like nginx return a bare HTML page and write the reason to the error log.

If the request is well-formed but the values fail validation, 422 is more precise. If the credentials are the problem, it's 401.

Source: RFC 9110 §15.5.1.

Common causes

  • Malformed JSON: a trailing comma, single quotes, an unescaped newline, or a body stringified twice so the server receives a JSON string where it expected an object.
  • A missing or wrong Content-Type, so the server's parser rejects the body, e.g. form-encoded data sent to a JSON-only endpoint.
  • nginx 400 Bad Request: Request Header Or Cookie Too Large: bloated cookies or a huge Authorization token exceed large_client_header_buffers.
  • nginx 400 The plain HTTP request was sent to HTTPS port: something is speaking plain HTTP to port 443.
  • Invalid characters in the URL: unencoded spaces, a % not followed by two hex digits.
  • A malformed header line, or no Host header on HTTP/1.1. Usually a hand-written client or a misconfigured proxy.
  • Express with express.json(): invalid JSON throws a SyntaxError that becomes a 400 with type: 'entity.parse.failed'.

How to debug and fix a 400

Reproduce it with curl

-v prints the exact request headers. In DevTools, right-click the failing request and choose Copy as cURL, then change one thing at a time until it works. Paste the body into a JSON validator first.

curl -v https://api.example.com/orders \
  -H 'Content-Type: application/json' \
  --data '{"sku": "A-1", "qty": 2}'

nginx: headers or cookies too large

The default is 4 8k. Raising it treats the symptom, so also find out why cookies are that big (many analytics cookies, session data stored client-side) or why the token carries so many claims.

# http or server block
large_client_header_buffers 4 16k;

Express: return a helpful 400 for bad JSON

An error-handling middleware (four arguments) can catch body-parser failures and return JSON instead of an HTML error page.

app.use(express.json());

// ... routes ...

app.use((err, req, res, next) => {
  if (err.type === 'entity.parse.failed') {
    return res.status(400).json({ error: 'invalid_json', detail: err.message });
  }
  next(err);
});

Client side: encode once, label correctly

Build query strings with URLSearchParams, stringify the body exactly once, and set Content-Type.

const params = new URLSearchParams({ q: 'a&b c', page: '2' });
const res = await fetch(`/api/search?${params}`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ tags: ['x', 'y'] }),
});

Headers that matter with 400

Content-Type
Tells the server which parser to use. A mismatch is one of the most common 400 causes.
Content-Length
If it doesn't match the actual body size, the message framing is invalid and the server must reject it.
Cookie / Authorization
The usual culprits when headers exceed the server's buffer limits.

400 vs similar status codes

  • 422 Unprocessable Content: The syntax is fine but the values are invalid. Use it for validation errors if you want to separate them from parse errors.
  • 401 Unauthorized: The request is fine but has no valid credentials.
  • 413 Content Too Large: The body is too big. nginx returns 400 for oversized headers but 413 for oversized bodies.
  • 431 Request Header Fields Too Large: The precise code for oversized headers. Many servers, nginx included, send 400 instead.

SEO impact of 400

For Googlebot, every 4xx except 429 is treated the same way: the URL isn't indexed, and drops out if it was. If Search Console reports 400s, look for URL parameters or malformed links that your server rejects.

Related status codes

Looking for another code? Search the full HTTP status codes list, or read which code your API should return in the REST API status codes guide.

Learn more

Browse all developer guides →

Frequently Asked Questions

Is a 400 Bad Request a client or server problem?▾

By definition the server is blaming the client: something in the body, URL, headers or cookies is invalid. In practice it can still be a server issue, such as a header limit set too low or an over-strict parser, so check the server or proxy logs for the exact reason.

How do I fix 400 Bad Request: Request Header Or Cookie Too Large?▾

As a visitor, clear that site's cookies. As the site owner, find what's bloating the headers (often too many cookies or a very large JWT) and, if needed, raise nginx's large_client_header_buffers, for example to 4 16k.

Should validation errors return 400 or 422?▾

Both are common. 400 is fine for everything if you return field-level details in the body. Many frameworks (Rails, FastAPI, Laravel) use 422 when the body parsed correctly but values are invalid, which lets clients separate fix-your-code errors from fix-your-input errors. Pick one convention and document it.