Quick answer
HTTP 400 Bad Request means the server could not process the request because it was malformed — often invalid JSON, a missing required field, or a wrong parameter.
What HTTP 400 means
400 Bad Request indicates a client-side error in the request itself. The server understood the request line but the payload, query parameters, or headers were malformed. In JSON APIs the single most common cause is a body that is not valid JSON — a trailing comma, a missing quote, or a truncated payload.
Common causes
- Invalid JSON syntax in the request body (trailing comma, missing quote, unescaped character)
- A required field or query parameter is missing
- A field has the wrong type (string where a number is expected)
- Malformed headers or an invalid
Content-Type
Example JSON error response
{
"error": "Bad Request",
"message": "Invalid JSON: unexpected token at position 42",
"status": 400
}
Raw HTTP response
HTTP/1.1 400 Bad Request
Content-Type: application/json
How to troubleshoot HTTP 400
- ✓ Validate your request body is well-formed JSON with the JSON Validator
- ✓ Check all required fields and parameters are present
- ✓ Confirm each field has the correct type
- ✓ Verify the
Content-Typeheader matches the body (e.g.application/json) - ✓ Format the payload with the JSON Formatter to spot syntax errors
400 vs 422 — what's the difference?
400 Bad Request means the request itself is malformed — for a JSON API, usually the body isn't valid JSON at all. 422 Unprocessable Entity means the JSON is syntactically valid but fails validation (a field is the wrong value, an email is malformed, a business rule is broken). Rule of thumb: if the parser can't even read the body, it's 400; if it reads fine but the data is wrong, it's 422.
Handling HTTP 400 in client code
A 400 is almost always a bug in the request your code built, not a server problem — so surface the server's error message rather than retrying. Retrying an identical malformed request will just 400 again:
const res = await fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
});
if (res.status === 400) {
const err = await res.json(); // read the server's reason
console.error('Bad request:', err.message);
return; // do NOT blindly retry a 400
}
The most common cause in JS is hand-building a JSON string instead of using JSON.stringify(), which introduces trailing commas or unquoted keys. If you're debugging a malformed body, paste it into the JSON Validator — and see how to read a minified JSON API response.
Returning 400 in different frameworks
| Framework | How to return 400 |
|---|---|
| Express (Node.js) | res.status(400).json({ error: "Bad Request" }) |
| Flask (Python) | return jsonify(error="Bad Request"), 400 |
| FastAPI (Python) | raise HTTPException(status_code=400, detail="...") |
| Spring Boot (Java) | ResponseEntity.badRequest().body(...) |
Frequently Asked Questions
What causes a 400 Bad Request in a JSON API?
Most often the request body is not valid JSON — a trailing comma, a missing quote, or a truncated payload. Other causes are missing required fields, wrong field types, or an incorrect Content-Type header.
How do I fix a 400 Bad Request?
Validate the request body as JSON, confirm all required fields are present and correctly typed, and check the Content-Type header. Pasting the body into a JSON validator quickly reveals syntax errors.
What is the difference between 400 and 422?
400 means the request is malformed (e.g. invalid JSON the server cannot parse). 422 means the JSON is valid but fails semantic validation. Use 400 for unparseable requests, 422 for valid-but-rejected data.
Should I retry a request that returned 400?
No. A 400 means the request was malformed, so retrying the identical request will fail the same way. Fix the request — correct the JSON, add the missing field, or set the right Content-Type — then send it again. Retries are appropriate for transient 5xx errors, not 400.
Why does my API return 400 with a valid-looking body?
Common culprits: a missing or wrong Content-Type: application/json header (so the server never parses the body as JSON), a trailing comma from hand-built JSON, or a field with the wrong type. Send the body through JSON.stringify() and confirm the Content-Type header.
Working with a JSON API response?
Format and inspect any response in your browser — nothing is uploaded.