HTTP 400 Bad Request indicates the server cannot process the request due to something perceived as a client error — malformed request syntax, invalid request message framing, or deceptive request routing. This is the generic client error response when no more specific 4xx code applies. In API design, 400 should include a descriptive error body explaining exactly what was wrong so the client can fix the request.
Response includes the status code, standard headers (including Content-Type), and a small diagnostic JSON body describing the request and returned status.
Simulator URL (copy in the app after load — not a normal link):
https://httpstatus.com/api/status/400
Example request:
curl -i "https://httpstatus.com/api/status/400"The server cannot or will not process the request due to an apparent client error.
On this code, Inspector focuses on semantics, headers, and correctness warnings that commonly affect clients and caches.
400 Bad Request (RFC 7231 Section 6.5.1) is the catch-all for client-side errors that don't fit a more specific 4xx code. Servers return 400 for: malformed JSON/XML bodies, invalid query parameters, missing required fields, type mismatches (string where number expected), request headers exceeding limits, and invalid URL encoding. Key design principle: always include machine-readable error details. A bare 400 without explanation forces developers to guess what's wrong. Best practices: use a consistent error schema like RFC 7807 Problem Details ({ type, title, status, detail, instance }) across all 4xx responses. 400 is not cacheable.
// Structured error responses with RFC 7807
app.post('/api/users', (req, res) => {
const errors = [];
if (!req.body.email) errors.push({ field: 'email', message: 'Required' });
if (!req.body.name) errors.push({ field: 'name', message: 'Required' });
if (req.body.email && !isValidEmail(req.body.email))
errors.push({ field: 'email', message: 'Invalid email format' });
if (errors.length > 0) {
return res.status(400).json({
type: 'https://api.example.com/errors/validation',
title: 'Validation Error',
status: 400,
detail: `${errors.length} validation error(s)`,
errors
});
}
// proceed...
});from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from pydantic import BaseModel, EmailStr, ValidationError
class CreateUser(BaseModel):
name: str
email: EmailStr
@app.exception_handler(ValidationError)
async def validation_handler(request: Request, exc: ValidationError):
return JSONResponse(status_code=400, content={
'type': 'validation_error',
'title': 'Bad Request',
'status': 400,
'errors': [{'field': e['loc'][-1], 'message': e['msg']}
for e in exc.errors()]
})@ControllerAdvice
public class ErrorHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, Object>> handleValidation(
MethodArgumentNotValidException ex) {
List<Map<String, String>> errors = ex.getBindingResult()
.getFieldErrors().stream()
.map(e -> Map.of("field", e.getField(),
"message", e.getDefaultMessage()))
.toList();
return ResponseEntity.badRequest().body(Map.of(
"type", "validation_error",
"title", "Bad Request",
"status", 400,
"errors", errors));
}
}type ValidationError struct {
Field string `json:"field"`
Message string `json:"message"`
}
func createUser(w http.ResponseWriter, r *http.Request) {
var req CreateUserRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeError(w, 400, "Invalid JSON", err.Error())
return
}
var errs []ValidationError
if req.Email == "" {
errs = append(errs, ValidationError{"email", "Required"})
}
if len(errs) > 0 {
w.WriteHeader(400)
json.NewEncoder(w).Encode(map[string]any{
"status": 400, "errors": errs})
return
}
}