Loading HTTP Status Codes…
Would different credentials change the answer?
Yes means 401: the caller has not proved who they are, and the WWW-Authenticate header tells them how. No means 403: identity is established and the answer is still no. The names are backwards — 401 is the unauthenticated one — which is why this pair is the most misused in HTTP.
May the client turn your POST into a GET?
302 lets it. RFC 9110 records that browsers have always rewritten the method for 302, so a redirected POST arrives as a bodyless GET. 307 forbids the rewrite: method and body survive. Redirect a form submission with 302 and the data silently disappears; use 303 if you want the GET, 307 if you want the POST.
The same question, permanently.
301 tolerates the method changing to GET; 308 does not. For a marketing URL that only ever serves GET, 301 is fine and is what caches and search engines are most used to. For an API path, 308 is the honest one — and it is also the one that will not turn a permanent PUT redirect into a lost request body.
Is the request wrong, or is the world wrong?
422 says the body is well-formed but invalid on its own terms: a negative quantity, a malformed email. Resending it unchanged will always fail. 409 says the body is fine but clashes with current state: the username is taken, the version is stale. Resending it later, or after a refetch, may well work.
Why does a teapot have a status code?
RFC 2324 defined the Hyper Text Coffee Pot Control Protocol as an April Fools joke in 1998, and 418 is its refusal to brew coffee in a teapot. RFC 7168 extended the joke to teapots asked for coffee. It has never been in the HTTP specification, an attempt to reclaim the number in 2017 was withdrawn after protest, and frameworks still ship it.
A number matches by prefix, so 41 lists the whole 41x row. Text matches the name, the meaning and the guidance.
Every registered code, in numeric order.
The request headers are acceptable and the client should send the body.
Send it when Only in reply to a request carrying Expect: 100-continue, so a large upload is not sent to a server that would reject it.
The server is changing to the protocol named in the Upgrade header.
Send it when The WebSocket handshake, and effectively nothing else in practice.
A WebDAV interim response saying the request was accepted but is not finished.
Send it when Never in new work: RFC 4918 removed it because it was unused and unhelpful.
Carries Link headers so the client can start preloading before the real response.
Send it when When the final response is slow to compute and the assets it will reference are known now.
The request succeeded and the body is the result.
Send it when The default success for GET, and for POST or PUT where the response carries the resulting state.
One or more resources were created.
Send it when A POST or PUT that made something new. Send a Location header pointing at it.
The request was accepted but has not been acted on yet, and may still fail.
Send it when Work handed to a queue. Give the client somewhere to poll for the outcome.
The payload was modified in transit by a proxy or transforming intermediary.
Send it when Sent by that intermediary, not by the origin server.
Success, and deliberately no body. Headers may still carry metadata.
Send it when A DELETE that succeeded, or a PUT whose result the client already has.
Success, and the client should clear the form that produced the request.
Send it when Data-entry screens that submit repeatedly. Rare on the web.
The body is the byte range the Range header asked for.
Send it when Resumed downloads and media seeking. Requires a Content-Range header.
The body is XML holding a separate status for each resource touched.
Send it when WebDAV operations over a collection, where one code cannot describe the outcome.
A binding already listed earlier in this Multi-Status response is not repeated.
Send it when Inside a 207 body, to keep a recursive WebDAV report finite.
The response is the result of applying instance manipulations to the current instance.
Send it when Delta encoding, which almost nothing implements.
Several representations exist and the client or user must pick.
Send it when Agent-driven negotiation. There is no standard format for the list, which is why it is rare.
The resource has a new permanent URL, and clients may rewrite the method to GET.
Send it when A URL that has genuinely moved for good, on a GET-shaped resource.
A temporary redirect that clients also rewrite to GET in practice.
Send it when Legacy code paths. New work wants 303 or 307, which say what they mean.
The result of the request is at another URL, retrieved with GET.
Send it when After a successful POST, so a refresh does not resubmit the form.
The cached copy is still current; no body is sent.
Send it when A conditional GET whose If-None-Match or If-Modified-Since still holds.
Deprecated. It once named a proxy the client had to use.
Send it when Never. It was a security problem and clients ignore it.
Reserved. Defined in an early draft, never standardised.
Send it when Never. The number is kept reserved so nothing reuses it.
A temporary redirect that forbids changing the method or dropping the body.
Send it when Any temporary redirect of a POST, PUT, PATCH or DELETE.
A permanent redirect that forbids changing the method.
Send it when A permanent move of anything that is not purely a GET target.
The server will not process the request because it is malformed.
Send it when Broken syntax: unparseable JSON, a missing required parameter, a header that makes no sense.
No valid credentials were supplied. The name is a misnomer for unauthenticated.
Send it when A missing, expired or invalid token. A WWW-Authenticate header is mandatory.
Reserved for future use, with no defined payment mechanism.
Send it when Some APIs use it for an unpaid account. Nothing interoperable depends on it.
The server understood who you are and is refusing anyway.
Send it when An authenticated caller without the right permission, or a rule that no credentials would satisfy.
No representation exists for this target, and the server will not say whether it ever did.
Send it when An unknown path, and deliberately in place of 403 when even the existence of the resource is private.
The target exists but does not support this method.
Send it when A POST to a read-only endpoint. An Allow header listing the supported methods is mandatory.
No representation matches the Accept headers sent.
Send it when Rarely worth sending; serving your default type is usually kinder than refusing.
Like 401, but the proxy is the one demanding credentials.
Send it when Sent by a proxy, with a Proxy-Authenticate header.
The server gave up waiting for the request to arrive.
Send it when An idle connection the server is closing. Not for a slow handler — that is 504.
The request conflicts with the current state of the resource.
Send it when A duplicate that must be unique, a lost update, or an edit against a stale version.
The resource existed and has been removed for good.
Send it when A deleted account or retired endpoint, when telling crawlers to stop asking is worth the bookkeeping.
The request needs a Content-Length header and did not have one.
Send it when A server that cannot accept a chunked body.
A condition in If-Match or If-Unmodified-Since did not hold.
Send it when Optimistic concurrency: the ETag the client sent no longer matches.
The body is larger than the server is willing to process.
Send it when An upload over your limit. Renamed from Payload Too Large in RFC 9110.
The request target is longer than the server will accept.
Send it when A GET whose query string should have been a POST body.
The body is in a format this endpoint does not accept.
Send it when XML sent to a JSON-only API, or a missing Content-Type on a request that needs one.
The requested byte range lies outside the resource.
Send it when A resumed download against a file that has since shrunk.
The Expect header cannot be met.
Send it when In practice, only in reply to an Expect the server does not support.
The server refuses to brew coffee because it is a teapot.
Send it when Never seriously. It is a 1998 April Fools joke that survives because implementers kept it.
This connection cannot produce a response for the authority requested.
Send it when HTTP/2 connection reuse, where one TLS certificate covers hosts served by different backends.
The syntax is fine but the content is semantically wrong.
Send it when Validation failures: a well-formed JSON body with an email field that is not an email.
The resource is locked.
Send it when WebDAV, against a resource someone else holds a lock on.
The request failed because an earlier request it depended on failed.
Send it when Inside a WebDAV batch where one member has already failed.
The server will not risk processing a replayable early-data request.
Send it when TLS 1.3 0-RTT data on a non-idempotent request.
The client must switch to a different protocol to continue.
Send it when Forcing TLS or a newer HTTP version. Requires an Upgrade header.
The request must be conditional.
Send it when An unconditional PUT to a resource where a lost update would matter.
The client has sent too many requests in a given period.
Send it when Rate limiting. Send Retry-After so the client knows when to come back.
The headers are collectively or individually too large.
Send it when Usually a cookie that has grown unbounded.
Access is denied as a result of a legal demand.
Send it when A takedown or a geographic block, with a Link header describing the blocking authority.
The server hit an unexpected condition and cannot be more specific.
Send it when An unhandled exception. Anything you can describe deserves a narrower code.
The server does not support the functionality the method requires.
Send it when A method the server does not recognise at all. Compare 405, which is per-resource.
A proxy got an invalid response from the server behind it.
Send it when Sent by the proxy: the upstream crashed, closed the connection or spoke nonsense.
The server cannot handle the request right now, but the condition is temporary.
Send it when Maintenance, an overloaded queue, a dependency that is down. Retry-After belongs here.
A proxy timed out waiting for the server behind it.
Send it when A handler slower than the gateway limit. Distinct from 408, which is about the request arriving.
The major HTTP version in the request is not supported.
Send it when Almost never, since version negotiation happens earlier.
Transparent negotiation has produced a circular reference.
Send it when A misconfigured negotiating server. Effectively a server bug report.
The server cannot store the representation needed to finish the request.
Send it when WebDAV, out of quota or out of disk.
An infinite loop was found while processing the request.
Send it when A WebDAV bind cycle that a recursive operation would never escape.
The request needs further extensions to be handled.
Send it when Never in new work: RFC 9110 records the mechanism as obsolete.
The client must authenticate to gain network access.
Send it when Captive portals, sent by the intercepting network rather than the origin.
Codes and names follow the IANA HTTP Status Code Registry; each entry cites the document that defines it.
Looking up what 412 means takes a second; deciding which code your own endpoint should return takes longer, and that is the decision this page is built around. Every registered code carries what it means, when to send it and the document defining it, and the search box matches a number by prefix or any text in the description, so “retry-after” finds 429 and 503 together.
The citations are worth reading. Most everyday codes were re-specified by RFC 9110 in June 2022, which obsoleted RFC 7231 and, before it, the relevant half of RFC 2616 — so an old answer citing 2616 is three revisions behind. The oddities keep their original homes: WebDAV contributed 207, 423 and 507 through RFC 4918, the rate-limiting codes arrived with RFC 6585, and legal blocking got 451 from RFC 7725.
This pair goes wrong most often, partly because the names mislead. 401 is called Unauthorized but means unauthenticated: the request arrived without usable credentials, and RFC 9110 §15.5.2 requires a WWW-Authenticate header saying how to supply them. 403 means the server knows exactly who is asking and is still saying no. The test is whether a different token would change the outcome — if it would, the answer is 401.
A third option is sometimes better than either. Where the existence of a resource is itself private, replying 404 to someone not entitled to see it leaks nothing, whereas 403 confirms the record exists — which is why the choice here is a security decision rather than a stylistic one. When a proxy rather than the origin wants credentials, the code is 407.
All four redirect. What separates them is whether the client may rewrite your POST into a GET: 302 and 301 permit it, 307 and 308 forbid it, and 301 and 308 are the permanent pair.
The permission is not theoretical. Early browsers rewrote the method on a 302 whatever the specification said, and the behaviour survives today — so a form POSTed to a URL answering 302 arrives as a GET with no body, and the submitted data is gone. RFC 9110 §15.4.4 gives 303 for when that conversion is what you want, which is the standard defence against a refresh resubmitting a payment. For an API that must keep the method and body, 307 or 308 is the only safe choice.
Both reject a request the server understood. 422 Unprocessable Content, now in RFC 9110 §15.5.21 after starting life in WebDAV, means the body parsed but its contents are invalid on their own terms — a quantity of −3, a date in the wrong century — so resending it unchanged can never succeed. 409 Conflict means the body is fine and the world disagrees with it: the email address is taken, the document was edited since you fetched it. Resending after a refetch may well work, which is a different instruction to the client.
418 is the famous one. RFC 2324, an April Fools joke from 1998, defined a protocol for controlling coffee pots and gave teapots a code with which to refuse to brew; RFC 7168 later extended the joke. It has never been part of HTTP, an attempt to free the number in 2017 was abandoned after public objection, and it remains implemented in framework after framework as a piece of shared folklore.
It is common and it is a poor idea. Caches, retry logic, monitoring and client libraries all key off the status line, so a failure wearing a 200 is invisible to every one of them. Let the status code say what happened and the body carry the detail.
429 Too Many Requests, from RFC 6585 §4, together with a Retry-After header giving either a delay in seconds or a date. Without that header the client has no basis for a backoff and will usually guess badly.
Both come from something in front of your application. A 502 means the proxy got an invalid or truncated response from upstream; a 504 means it got nothing in time. The first points at a crash, the second at a slow handler or a timeout set too low.
404 is enough for most cases. 410 earns its bookkeeping when you want crawlers to stop asking permanently: it asserts the resource existed and will not return, which 404 deliberately declines to say either way.
Because they are not in the IANA registry. Each was invented by a single vendor — 499 by nginx, for a client that disconnected before replying — so nothing outside that ecosystem is obliged to understand them.