HTTP Status Codes
debt(d7/e3/b3/t7)
Closest to 'only careful code review or runtime testing' (d7). The detection_hints indicate `automated: no`, and while tools like Postman, Spectral, and OWASP ZAP are listed, they require deliberate API contract inspection or manual testing rather than catching misuse at compile time or via default linting. A 200-with-error-body pattern is invisible until a developer or tester actively exercises the endpoint and inspects the response.
Closest to 'simple parameterised fix' (e3). The quick_fix lists a clear canonical set of status codes covering 95% of cases. Fixing misuse typically means changing a return value or response-building call in one controller or handler — a small targeted change per endpoint, but potentially touching several files if the pattern is widespread. The fix per instance is trivial, making e3 the right anchor.
Closest to 'localised tax' (b3). The misuse applies to web/API contexts only and tends to be localised to specific endpoints or a shared response-building utility. It does not reshape the entire architecture, but every endpoint that misuses status codes imposes a persistent maintenance and debugging cost on API consumers and monitoring systems. Slightly worse than b1 but far from system-defining.
Closest to 'serious trap' (t7). The canonical misconception — '200 OK means everything is fine' — is directly cited in the metadata. Many APIs return 200 with an error payload, a pattern that directly contradicts how HTTP clients, monitoring tools, and retry logic are designed to behave. The 401 vs 403 confusion and 404-for-auth-failure leakage are additional documented gotchas that contradict intuitive assumptions, placing this solidly at t7.
Also Known As
TL;DR
Explanation
HTTP status codes are grouped into five classes: 1xx (informational), 2xx (success), 3xx (redirection), 4xx (client error), and 5xx (server error). Using correct codes is essential for caching, retry logic, API clients, and debugging. A 200 OK with an error body, or a 500 for a validation failure, breaks every layer that depends on HTTP semantics.
Diagram
flowchart TD
REQ[HTTP Request] --> RANGE{Status range}
RANGE -->|1xx| INFO2[Informational<br/>100 Continue<br/>101 Switching Protocols]
RANGE -->|2xx| SUCCESS[Success<br/>200 OK<br/>201 Created<br/>204 No Content]
RANGE -->|3xx| REDIRECT[Redirect<br/>301 Permanent<br/>302 Temporary<br/>304 Not Modified]
RANGE -->|4xx| CLIENT[Client Error<br/>400 Bad Request<br/>401 Unauthorized<br/>403 Forbidden<br/>404 Not Found<br/>422 Unprocessable<br/>429 Rate Limited]
RANGE -->|5xx| SERVER[Server Error<br/>500 Internal Error<br/>502 Bad Gateway<br/>503 Service Unavailable]
style SUCCESS fill:#238636,color:#fff
style CLIENT fill:#f85149,color:#fff
style SERVER fill:#f85149,color:#fff
style REDIRECT fill:#d29922,color:#fff
style INFO2 fill:#1f6feb,color:#fff
Common Misconception
Why It Matters
Common Mistakes
- Returning 200 OK with an error body — clients cannot detect the failure without parsing every response.
- Using 500 for validation errors — 422 Unprocessable Entity or 400 Bad Request is correct for client-supplied bad data.
- Returning 404 for authorisation failures — use 403 Forbidden; 404 leaks that the resource exists.
- Not returning 429 Too Many Requests with a Retry-After header for rate-limited responses.
Code Examples
// 200 OK with error — breaks client error detection:
return response()->json(['error' => 'User not found'], 200); // Wrong
// Correct status codes:
return response()->json(['message' => 'Not found'], 404);
return response()->json(['errors' => $validation], 422);
return response()->json(['message' => 'Forbidden'], 403);
// Semantic status codes:
return response()->json($user, 200); // GET success
return response()->json($created, 201); // POST created
return response()->json(null, 204); // DELETE success
return response()->json($errors, 422); // Validation failed
return response()->json(['message' => 'Not found'], 404);