WierdX — Programming Reference All tutorials →
Developer reference · Practical tutorials · CS fundamentals
HTTP & Networking

How HTTP Status Codes Work

Status codes are how the server tells the client what happened to a request. Getting them right in your API is as important as the response body — maybe more so.

Published April 18, 2026

Every HTTP response starts with a three-digit status code. The first digit defines the class of response. Clients and infrastructure (browsers, proxies, caches, monitoring tools) all make decisions based on the status code before ever looking at the body.

The five classes

  • 1xx Informational — request received, continuing process. Rarely seen in application code; 101 Switching Protocols is used for WebSocket upgrades.
  • 2xx Success — the request was successfully received, understood, and accepted.
  • 3xx Redirection — further action is needed to complete the request. Usually a Location header tells the client where to go.
  • 4xx Client Error — the request contains bad syntax or cannot be fulfilled. The client is responsible for the problem.
  • 5xx Server Error — the server failed to fulfil a valid request. The server is responsible.

The 2xx codes in practice

200 OK is the all-purpose success code. Use it for successful GET, PUT, and PATCH responses when you're returning a body.

201 Created signals that a POST request resulted in a new resource. Include a Location header pointing to the new resource's URL. Don't use 200 for creates — 201 tells the client something was added to the system.

204 No Content is success with no response body. The right choice for DELETE, or for PUT/PATCH when you don't need to return the updated resource. Returning 200 with an empty body is technically valid but 204 is cleaner.

202 Accepted means the request has been accepted for processing but processing has not been completed. Use this for async operations: "We got your request; check back later or we'll notify you."

The 3xx codes

301 Moved Permanently: the resource has a new permanent URL. Browsers and crawlers will update their records. Use when you're restructuring URLs and want the old ones to redirect forever.

302 Found (and 303 See Other, 307 Temporary Redirect): temporary redirections. Use 307 when you want the method and body preserved on redirect. Use 303 when a POST should redirect to a GET after processing (the standard form submission pattern).

304 Not Modified: the client's cached version is still current. The server returns no body; the client uses its cache. Requires the client to have sent If-None-Match or If-Modified-Since.

The 4xx codes you'll use most

400 Bad Request: the request is malformed. Missing required fields, invalid JSON, wrong content type. The client sent something wrong and should not retry without fixing it.

401 Unauthorized (despite the name, this means "unauthenticated"): the client is not authenticated. No credentials, or credentials that don't parse. The client should authenticate and retry.

403 Forbidden: the client is authenticated but does not have permission for this resource. Don't retry with the same credentials; you'd need different ones or a role change.

404 Not Found: the resource doesn't exist at this URL. Also commonly used when a resource exists but the current user is not allowed to know about it (to avoid leaking existence).

409 Conflict: the request conflicts with the current state of the resource. Typical cases: trying to create a user with an email that already exists; trying to update a resource based on a stale version.

422 Unprocessable Entity: the request is syntactically valid but semantically incorrect. Many frameworks use this for validation failures (field values that don't meet business rules) where 400 would be used for structural/parse errors.

429 Too Many Requests: rate limiting. Include a Retry-After header so clients know when they can try again.

5xx codes

500 Internal Server Error: an unhandled exception or unexpected state. The server encountered an error and doesn't know what to do. Usually means a bug.

502 Bad Gateway and 503 Service Unavailable: typically generated by reverse proxies (nginx, load balancers) when upstream servers are unreachable or returning errors. Your application code usually doesn't emit these; your infrastructure does.

503 Service Unavailable: the server is temporarily unable to handle requests. Typically deployment, maintenance, or overload. Include a Retry-After header.

The most common mistake: abusing 200

Returning 200 OK with an error message in the body breaks everything. Your monitoring won't alert on errors. Your HTTP clients will think the request succeeded. Your rate-limiting infrastructure won't distinguish between good and bad responses.

// Wrong: 200 with error in body
HTTP/1.1 200 OK
{"success": false, "error": "User not found"}

// Right: use the appropriate error code
HTTP/1.1 404 Not Found
{"error": {"code": "USER_NOT_FOUND", "message": "No user with id 42."}}

Status codes are a contract with every piece of HTTP infrastructure in the chain, not just your direct clients. Use them correctly and you get error detection, caching, monitoring, and retry logic for free.