400 Bad Request: what it means and how to fix it

The server couldn't understand the request. The fixes for visitors (usually cookies) and for developers: malformed JSON, missing parameters and headers a proxy refuses.

· 4 min read · By the Spot Downtime team

400 Bad Request is the server saying “I can't make sense of what you sent”. Unlike a 500, the server isn't broken: it looked at the request and rejected it before doing any real work. The trick is finding out which part of the request it didn't like, because the error page rarely says.

If you're a visitor seeing it

Almost every 400 a normal visitor sees comes from something stored in the browser, not from the site itself:

  • Corrupted or oversized cookies. Clear the cookies for that one site (not your whole browser) and reload. nginx shows this case as 400 Bad Request: Request Header Or Cookie Too Large.
  • A mangled link. A URL with a stray %, a space or a broken encoding. Retype the address or go to the home page.
  • A stale form. Submitting a form that sat open for hours can send an expired security token. Reload the page and submit again.

If it works in a private window, it was cookies or cache. If it fails everywhere, the problem is on the site's side.

If it's your site or API

Malformed body

The most common API cause: invalid JSON (a trailing comma, single quotes, an unescaped character) or a body that doesn't match the Content-Type header. Validate the exact bytes you send, not the object you think you send:

bash
curl -i https://api.example.com/orders \
  -H "Content-Type: application/json" \
  -d '{"sku": "A-100", "qty": 2}'

A well-behaved API puts the reason in the response body, such as {"error": "qty must be a number"}. Read it before anything else. (If the body is valid JSON but the values are wrong, many APIs use 422 instead.)

Missing or invalid parameters

A required query parameter that's missing, a date in the wrong format, an ID that isn't a number. Compare the request to the API docs field by field.

Headers the server refuses

Headers that are too large, duplicated (two Host headers), or invalid for the protocol. Proxies are stricter than application servers, so a request that works directly against your app can get a 400 from nginx or a load balancer in front of it.

HTTP sent to an HTTPS port

nginx answers 400 The plain HTTP request was sent to HTTPS port when something talks plain HTTP to port 443. Usually it's a health check, a load balancer or a script configured with http://example.com:443.

Finding which request failed

Look in the access log of whatever sits closest to the client. If the 400 is in nginx's log but the request never reached your application's log, the proxy rejected it, and its error.log usually says why:

bash
sudo grep '" 400 ' /var/log/nginx/access.log | tail -n 20
sudo tail -n 50 /var/log/nginx/error.log
HTTP headers checkerSee the exact status code and response headers a URL returns, and every redirect along the way.

Should a 400 wake anyone up?

One client sending a bad request is that client's bug. But if your own health check or home page starts returning 400, something changed on your side, often a proxy rule or a header limit in a new deploy. That's worth an alert.

Spot Downtime treats any 4xx from a monitored URL as down, so a broken proxy rule shows up as an incident with the status code attached, not as a support ticket a day later.

Keep reading