Reference
HTTP status code reference
Every status code in the IANA registry, with its official reason phrase, a plain explanation, the defining RFC and a link straight to the code, plus the vendor codes from nginx and Cloudflare that are not in the registry.
74 codes
1xx Informational
An interim response. The server is reporting connection status or request progress and a final response is still coming. A client has to be able to read these even when it did not ask for one. RFC 9110 §15.2
The server has read the start of the request and wants the rest of it.
A client that expects to send a large body can send `Expect: 100-continue` with the headers and wait before sending the body. A 100 means the server has not rejected the request so far and wants the content; the client sends the body and discards the 100. If the request carried no 100-continue expectation, the client just ignores the interim response.
The server agrees to change protocol on this connection, as the client asked.
The client asks with an Upgrade header and the server answers 101 with its own Upgrade header naming the protocol that takes over. This is how a WebSocket handshake completes, which is where most developers see it. After the 101, the connection no longer carries HTTP messages.
102 Processing
RFC 2518 §10.1A WebDAV server is still working on a request that takes a long time.
RFC 2518 defined it so a server could tell the client it has the complete request but has not finished acting on it, suggested for anything taking longer than about 20 seconds. It keeps a client from timing out during a slow WebDAV operation. RFC 4918, which obsoletes RFC 2518, removed the code and states that its registration should continue to reference RFC 2518.
Registry note. Removed by RFC 4918, the current WebDAV specification; the registry still cites RFC 2518.
103 Early Hints
RFC 8297 §2Header fields the final response will probably carry, sent early so the browser can start fetching.
The server sends a 103 with Link headers before it has finished building the real response, so the browser can start preloading stylesheets, scripts or fonts. The hints are speculative: they do not replace the headers on the final response, and evaluating them must not change how that response is processed. A client that does not understand 103 simply waits for the final status.
104 Upload Resumption Supported
draft-ietf-httpbis-resumable-upload-05An interim response telling the client that this upload can be resumed if it breaks.
It belongs to the in-progress resumable uploads work in the HTTP working group, where the server answers an upload with 104 and a handle the client can use to ask how much arrived and carry on from there. Nothing is standardised yet. The registry holds the code as a temporary registration, so treat it as experimental rather than something to implement against.
Registry note. Temporary registration from an Internet-Draft; the registry entry expires 2026-11-13.
2xx Successful
The request was received, understood and accepted. Which 2xx code you get says what the server did and what, if anything, it sent back. RFC 9110 §15.3
The request succeeded, and the response body is the result.
What the body contains depends on the method: the resource itself for GET, the result of the action for POST, the status of the action for PUT and DELETE. A 200 is expected to carry content unless the framing says the content has zero length; if a successful request has nothing to return, 204 is the better answer. 200 responses are heuristically cacheable unless cache headers say otherwise.
The request succeeded and one or more new resources now exist.
Send it from a POST or PUT that created something, with a Location header pointing at the primary new resource; if there is no Location, the new resource is the request URI itself. The body usually describes and links to what was created. Use 200 instead when the request succeeded without creating anything.
The request was accepted for processing, but nothing has happened yet.
It is deliberately noncommittal: the work is queued, might be rejected later when it actually runs, and HTTP has no way to send you the eventual result. Use it when a job runs out of band and you do not want to hold the connection open. The body should describe the current state and point at a status endpoint the client can poll.
203 Non-Authoritative Information
RFC 9110 §15.3.4The request succeeded, but a proxy changed the body on the way back.
A transforming proxy that rewrites a response, for example by recompressing images, sends 203 instead of 200 so the recipient knows the content is not what the origin server sent. It matters mostly for caching, since the transformed copy may only be valid along the same path. It is rare on the modern web.
The request succeeded and there is deliberately nothing in the response body.
The headers still describe the target resource after the action was applied, so a 204 to a PUT can carry the new ETag. It is the usual answer to a successful DELETE, and to a save action where the client should stay where it is. A 204 ends at the end of the header section and cannot contain content or trailers, so do not attach a body.
205 Reset Content
RFC 9110 §15.3.6The request succeeded and the client should clear the form it was submitted from.
It was designed for data entry: the user fills in a form, submits it, and the client resets the fields ready for the next entry. A server must not send content with a 205. Almost nothing uses it now, since applications handle the reset themselves.
The server is returning only the byte ranges the client asked for.
It answers a request with a Range header, and it is what makes resumable downloads and video seeking work. The client must read Content-Type and Content-Range to see which parts arrived and whether more requests are needed. A server is free to return fewer ranges than asked for, or to ignore Range entirely and send a plain 200.
207 Multi-Status
RFC 4918 §11.1One WebDAV response carrying a separate status for each of several resources.
A WebDAV method such as PROPFIND acts on many resources at once, so the body is an XML multistatus document with a status per resource. The 207 itself says nothing about whether the individual operations worked. Outside WebDAV you will rarely meet it.
208 Already Reported
RFC 5842 §7.1A WebDAV collection was listed earlier in the same multistatus response, so it is not repeated.
When several bindings point at the same collection, a deep PROPFIND would otherwise enumerate its members again and again. The first binding is reported with 200 and the rest with 208, with no entries for their descendants. It only appears inside a 207 body, and only for `Depth: infinity` requests.
226 IM Used
RFC 3229 §10.4.1The response is the result of applying delta encoding to the resource.
The client asks with an A-IM header listing instance manipulations, and the server answers 226 with the result rather than the whole resource, typically a diff against a copy the client already has. The response must carry an ETag for the current instance. Delta encoding in HTTP never saw wide deployment.
3xx Redirection
The client has to do something else to finish the request, usually fetch a different URL from the Location header. 304 is the odd one out: it points the client at its own cache. RFC 9110 §15.4
300 Multiple Choices
RFC 9110 §15.4.1The resource has several representations and the client has to pick one.
The server lists the alternatives so the user or the user agent can choose, and may add a Location header for its own preferred choice. HTTP never standardised a format for that list, which is the main reason the code is barely used. It is heuristically cacheable.
The resource has a new permanent URL, given in the Location header.
Use it when an address has changed for good and you want links and search engines updated. RFC 9110 notes that for historical reasons a user agent may change the request method from POST to GET when following it, and says to use 308 instead if that is undesirable. A 301 is heuristically cacheable, so clients can remember it for a long time; be sure before you send one.
The resource is temporarily at a different URL; keep using the original one.
It is the default redirect of most web frameworks. RFC 9110 carries the same historical note as for 301: a user agent may change the request method from POST to GET, and 307 exists for when that is undesirable. Because the move is temporary, clients should keep requesting the original URI.
Look at this other URL with a GET to see the result of what you just did.
It is the post/redirect/get pattern in one status code: a POST finishes, the server answers 303, and the client issues a GET against the Location URL so the result has its own bookmarkable, cacheable address. The redirect target is explicitly not equivalent to the original URI. It applies to any method, and switching to GET is the defined behaviour rather than a historical accident.
Your cached copy is still good, so nothing is being sent.
It answers a conditional GET or HEAD, one carrying If-None-Match or If-Modified-Since, whose condition turned out false, meaning the copy the client already has is current. The server must repeat the header fields that matter for caching, such as ETag, Date, Cache-Control and Vary, and must send no body. The client reuses its stored representation as if it had received a 200.
305 Use Proxy
RFC 9110 §15.4.6A withdrawn code that once told the client to repeat the request through a proxy.
RFC 9110 states that it was defined in a previous version of the specification and is now deprecated. Browsers never implemented it consistently, and letting a server redirect a client onto an arbitrary proxy was a security problem. Do not send it, and treat it as an error if you receive it.
Registry note. Deprecated by RFC 9110 §15.4.6.
306 (Unused)
RFC 9110 §15.4.7A code from an old draft that is no longer used and is reserved.
RFC 9110 §15.4.7: "The 306 status code was defined in a previous version of this specification, is no longer used, and the code is reserved." It has no reason phrase of its own in the registry, which lists it as "(Unused)". It appears in lists like this one only so the number is accounted for.
Registry note. Unused and reserved. The registry lists the code with no reason phrase.
Temporarily somewhere else, and the client must keep the same method and body.
RFC 9110 says the user agent MUST NOT change the request method if it redirects automatically, so a POST stays a POST. That is the whole difference from 302. Use it for temporary moves where the method matters, and keep requesting the original URI in future.
Permanently somewhere else, and the client must keep the same method and body.
It is 301 without the method rewriting, defined the same way as 307 but permanent. RFC 9110 notes the code is much younger than its siblings, dating from June 2014, so it might not be recognised everywhere. Like 301 it is heuristically cacheable and can be remembered for a long time.
4xx Client error
The client seems to have erred. The request as sent will not work, and repeating it unchanged will not help. These codes apply to any request method. RFC 9110 §15.5
The server will not process the request because something about it looks wrong.
The RFC gives malformed syntax, invalid message framing and deceptive routing as the examples, so it is properly about the request itself rather than the data inside a well-formed body. In practice it is also the catch-all many APIs return for failed validation. Repeating the same request will not help; fix the request first.
You are not authenticated, or the credentials you sent were not accepted.
The name is misleading: this is about authentication, not permissions. A server sending 401 MUST include a WWW-Authenticate header with at least one challenge, and a client may retry with a new or replaced Authorization header. If credentials were sent and still got 401, they were refused.
402 Payment Required
RFC 9110 §15.5.3Reserved for future use; there is no defined behaviour.
RFC 9110 says only that the code is reserved for future use. No payment mechanism was ever standardised around it. Some APIs use it for billing problems, but that is a private convention, so clients cannot rely on any particular meaning.
Registry note. Reserved for future use.
The server understood the request and refuses to do it.
If credentials were provided, the server considers them insufficient, and the client should not repeat the request with the same ones. A request can also be forbidden for reasons that have nothing to do with credentials. A server that does not want to admit the resource exists may answer 404 instead.
There is nothing at this address, or the server will not say that there is.
It says nothing about whether the absence is temporary or permanent. RFC 9110 prefers 410 when the server knows the condition is likely permanent. It is heuristically cacheable, which surprises people whose 404s stick around in a CDN.
The server knows this method but the resource does not support it.
A POST to a read-only endpoint is the usual cause. The origin server MUST include an Allow header listing the methods the resource does support, so the response tells the client what to send instead. If the server does not recognise the method at all, 501 is the right answer.
Nothing the server can send matches the Accept headers the client sent.
It comes from proactive content negotiation: the client restricted the media types, languages or encodings it will take, and the server has no matching representation and will not send a default. The server should list the available alternatives in the body. Many servers prefer to ignore the negotiation headers and send their default representation instead.
407 Proxy Authentication Required
RFC 9110 §15.5.8Like 401, but it is the proxy that wants credentials, not the destination server.
The proxy MUST send a Proxy-Authenticate header with a challenge, and the client retries with Proxy-Authorization. It is a normal sight on corporate networks that route traffic through an authenticating proxy. Nothing about the target server is implied.
The server gave up waiting for the rest of the request.
It means the complete request never arrived in the time the server was prepared to wait, often because an idle keep-alive connection was closed. A client with a request still in flight may repeat it, on a new connection if the old one is no longer usable. It is about receiving the request, not about how long the server took to answer, which is 504.
The request clashes with the current state of the resource.
It is most likely on a PUT, for example when the version being written conflicts with a change someone else made. It is used where the user could resolve the conflict and try again, so the body should carry enough detail to work out what clashed. APIs also use it for duplicate-creation attempts such as an already registered email address.
It was here, it is deliberately gone, and it is not coming back.
Use it when you know the removal is permanent and you want remote links taken down; use 404 when you do not know. It suits expired promotions, retired API versions and pages removed on purpose. It is heuristically cacheable, and there is no obligation to keep serving it forever.
411 Length Required
RFC 9110 §15.5.12The server refuses a request whose body has no Content-Length.
It appears when a client streams a body with chunked transfer encoding to a server that insists on knowing the size up front. The client may repeat the request with a valid Content-Length header. Buffering the body to measure it is the usual fix.
A condition attached to the request was false, so the server did not act.
It answers a request carrying If-Match, If-Unmodified-Since or a similar header whose condition failed when tested on the server. That is how optimistic concurrency works: the write is refused because the resource changed since you read it. Fetch the current version, reapply your change and retry.
The request body is bigger than the server is willing to handle.
Upload limits in web servers, proxies and API gateways produce it constantly. The server may close the connection rather than read the rest. If the limit is temporary the server should send Retry-After; otherwise send less, or use an upload endpoint built for large files. RFC 9110 renamed it from "Payload Too Large", so older tools may show that phrase.
414 URI Too Long
RFC 9110 §15.5.15The request URL is longer than the server will interpret.
RFC 9110 calls it rare and blames a POST wrongly converted to a GET with a long query string, a redirect loop that keeps appending to the path, or an attacker probing for buffer problems. Move the data into a request body. It is heuristically cacheable.
The body is in a format this endpoint does not accept.
The problem may be the Content-Type, the Content-Encoding, or what the server finds when it inspects the data. Sending form-encoded data to an endpoint that only takes JSON is the everyday cause. The server can answer with Accept or Accept-Encoding to say what it would have taken.
416 Range Not Satisfiable
RFC 9110 §15.5.17None of the requested byte ranges can be served.
It usually means the range starts past the end of the resource, but a server may also refuse an excessive number of small or overlapping ranges as a denial-of-service risk. A server answering a byte-range request should include Content-Range with the current length so the client can recalculate. Clients cannot count on receiving it, since servers are free to ignore Range and send a full 200.
417 Expectation Failed
RFC 9110 §15.5.18The server cannot meet the expectation in the request Expect header.
In practice the only expectation in use is `Expect: 100-continue`, so this is what a server that will not handle it can answer. At least one server on the path could not satisfy it. Retry without the Expect header.
418 (Unused)
RFC 9110 §15.5.19The teapot joke code, reserved so nothing else can claim the number.
RFC 9110 §15.5.19 explains that RFC 2324 was an April 1 RFC that lampooned the abuse of HTTP, that its application-specific 418 "has been deployed as a joke often enough for the code to be unusable for any future use", and that 418 is therefore reserved in the registry. The registry lists it as "(Unused)" with no reason phrase. The RFC adds that it could be reassigned in future if the 4xx range runs short.
Registry note. Unused and reserved. The registry lists the code with no reason phrase.
421 Misdirected Request
RFC 9110 §15.5.20This server cannot answer for the host in the request.
It is sent when a request arrives at a server not configured for that origin, or over a connection whose context does not match, which happens when HTTP/2 reuses one connection for several hostnames sharing a certificate. A client may retry over a different connection even when the method is not idempotent. A proxy must never generate it.
The body parsed fine but the instructions in it cannot be carried out.
The server understood the content type, so 415 does not apply, and the syntax is correct, so 400 does not fit either; the content is just semantically wrong. It is the code most APIs use for validation failures on a well-formed JSON body. RFC 9110 renamed it from WebDAV's "Unprocessable Entity", which is still the phrase many libraries print.
423 Locked
RFC 4918 §11.3The WebDAV resource involved in the request is locked.
Either the source or the destination of the method is locked, and the response should carry a precondition or postcondition code such as `lock-token-submitted`. Supplying the right lock token in the If header is the way through. It belongs to WebDAV.
424 Failed Dependency
RFC 4918 §11.4This part of the request failed because another part it depended on failed.
When one command in a WebDAV PROPPATCH fails, the rest report 424 rather than being attempted. It marks work that was skipped, not work that was tried and broke. Fix the underlying failure and resend.
425 Too Early
RFC 8470 §5.2The server will not risk processing a request that arrived in TLS early data.
TLS 1.3 lets a client send data in the first flight, before the handshake completes, which saves a round trip but allows an attacker to replay that data. A server that does not want to take the risk answers 425, and the user agent is expected to retry once the handshake is done, never again in early data. A server should only send it when the request came in early data or carried `Early-Data: 1`.
426 Upgrade Required
RFC 9110 §15.5.22The server wants the client to switch protocols before it will answer.
The server refuses the request over the current protocol but might accept it over another, and MUST send an Upgrade header naming what it wants. The RFC example asks a client to move to HTTP/3.0. A server can use it to insist on an encrypted or newer protocol version.
428 Precondition Required
RFC 6585 §3The server insists the request be conditional.
It exists to stop the lost-update problem, where two clients read a resource and the second write silently overwrites the first. The server refuses the unconditional write, and the response should explain how to resend it, typically by adding If-Match with the ETag you read. Responses with 428 must not be stored by a cache.
You have been rate limited.
The client sent too many requests in a given amount of time. The response should explain the limit and may include Retry-After saying how long to wait; back off for at least that long, ideally with jitter. The specification deliberately does not define how the server identifies a user or counts requests. Responses with 429 must not be stored by a cache.
431 Request Header Fields Too Large
RFC 6585 §5The request headers are too big for the server to accept.
It covers both the headers as a whole and one oversized field, and in the latter case the response should name the field at fault. Enormous cookies are the usual cause. Trim the headers and resend. Responses with 431 must not be stored by a cache.
451 Unavailable For Legal Reasons
RFC 7725 §3Access is blocked because of a legal demand.
The blocking server need not be the origin; the code was written with ISPs and search engines in mind. The response should explain the demand: who made it, under what law, and which people and resources it covers, and can carry a Link header with `rel="blocked-by"`. RFC 7725 adds that the code "implies neither the existence nor nonexistence of the resource named in the request", that a 451 response is cacheable by default, and closes its acknowledgements with "Thanks also to Ray Bradbury."
5xx Server error
The server knows it failed or cannot do what was asked. The request may have been fine, so a retry can succeed, especially for 502, 503 and 504. RFC 9110 §15.6
The server hit an unexpected condition and could not finish the request.
It is the generic server-side failure: an unhandled exception, a bad configuration, a crash in application code. It says nothing about the cause on purpose, so the answer is always in the server logs rather than the response. A retry may work if the failure was transient, but nothing about the code promises that.
The server does not support what the request needs at all.
RFC 9110 calls it the right answer when the server does not recognise the request method and could not support it for any resource. That is the difference from 405, which is about a method the server knows but this resource does not allow. It is heuristically cacheable.
A proxy or gateway got an invalid response from the server behind it.
The machine you reached is fine; the one it forwarded to answered with something unusable, or refused the connection. It is the classic sign of an application process that is down or crashing behind nginx, a load balancer or a CDN. Check the upstream service, not the proxy.
The server is temporarily unable to handle the request.
RFC 9110 gives temporary overload and scheduled maintenance as the causes, and says the condition will likely be over after some delay. The server may send Retry-After to say how long to wait, as a number of seconds or an HTTP date. The RFC notes that an overloaded server is not obliged to use 503; some simply refuse the connection.
A proxy or gateway waited for the server behind it and gave up.
The upstream server accepted the request but did not answer in time, so the difference from 502 is silence rather than a broken answer. Slow queries, exhausted worker pools and proxy timeouts set too low all produce it. Look at how long the upstream takes before raising the timeout.
505 HTTP Version Not Supported
RFC 9110 §15.6.6The server refuses the major HTTP version the request used.
It is about the major version in the request message, not a minor feature the server lacks. The server should describe why that version is unsupported and which protocols it does speak. You are most likely to see it from a malformed request line that a server reads as an impossible version.
506 Variant Also Negotiates
RFC 2295 §8.1A content negotiation loop caused by a server misconfiguration.
In transparent content negotiation the chosen variant is itself configured to negotiate, so it is not a proper end point and the process cannot terminate. It is an internal configuration error, which is why it is a 5xx. Transparent content negotiation is experimental and rarely deployed.
507 Insufficient Storage
RFC 4918 §11.5The server has no room to store what the request would write.
A WebDAV server sends it when it cannot store the representation needed to complete the method, and the condition is considered temporary. If the request came from a user action, the client must not repeat it automatically; wait for the user to ask again. Some object stores and file APIs reuse it outside WebDAV.
508 Loop Detected
RFC 5842 §7.2The server stopped because a request kept going round in circles.
It appears in WebDAV when a `Depth: infinity` operation runs into an infinite loop of bindings, for example a collection bound inside itself. The status means the whole operation failed, not just one branch. It is also the fallback for clients that do not understand 208.
510 Not Extended (OBSOLETED)
RFC 2774 §7An obsolete code from the HTTP extension framework, saying the request lacked a required extension.
RFC 2774 defined it for a resource whose access policy was not met, with the response describing the extensions the client would have to declare. The experiment was moved to Historic status and the registry now lists the code as obsoleted. Nothing current should send it.
Registry note. Obsoleted. The registry lists the phrase as "Not Extended (OBSOLETED)".
511 Network Authentication Required
RFC 6585 §6You have to log in to the network itself, not to the site you asked for.
It is meant for captive portals, the hotel and airport Wi-Fi gateways that intercept traffic until you accept the terms. The response should link to the page where credentials can be submitted rather than embedding the login form, because a browser would otherwise attribute that form to the site you originally requested. Intercepting proxies that return 200 with a login page instead are the reason so many captive portals confuse clients.
Unofficial vendor codes
These are not in the IANA registry and no RFC defines them. They turn up often enough in logs and browser tabs to be worth looking up, and each one below is described by the company that invented it. Do not build clients that depend on them.
An nginx configuration value that drops the connection instead of answering.
The nginx documentation for the `return` directive says "The non-standard code 444 closes a connection without sending a response header." It is used to hang up on unwanted traffic, such as requests for an unknown virtual host. Nothing is ever sent to the client, so 444 appears in nginx access logs, never on the wire.
The client went away before nginx had an answer for it.
nginx logs it when the connection is closed from the client side while the request is still being processed, typically a user navigating away or a caller whose own timeout expired. Like 444 it is a log value: there is nobody left to send it to. nginx defines it in its source as `NGX_HTTP_CLIENT_CLOSED_REQUEST 499`, but does not describe it in its published documentation, so treat the name as convention rather than a specification.
The origin answered Cloudflare with something Cloudflare could not make sense of.
Cloudflare documents it as occurring "when the origin server returns an empty, unknown, or unexpected response to Cloudflare". The causes it lists include origin crashes, a firewall at the origin blocking Cloudflare IPs, headers over 128 KB from oversized cookies, and malformed responses with no status line. It is a catch-all, so start with the origin logs.
The origin refused the connection from Cloudflare.
Cloudflare: "Error 521 occurs when the origin web server refuses connections from Cloudflare." Either the web server process is not running, or something at the origin is blocking Cloudflare IP ranges. The refusal is active, which is what separates it from 522 and 523.
Cloudflare could not complete a TCP connection to the origin in time.
Cloudflare documents two timeouts behind it: no SYN+ACK within 19 seconds of the SYN, or no acknowledgement of the resource request within 90 seconds once the connection is up. An overloaded origin, a dropped packet path or a firewall silently discarding traffic all produce it. Nothing answered, as opposed to 521 where the connection was actively refused.
Cloudflare has no route to the origin at all.
Cloudflare: "This error occurs when Cloudflare cannot contact your origin web server." Its documentation blames a network device between the two with no route to the origin address, and gives an over-broad VPC route such as 172.0.0.0/8 capturing Cloudflare traffic as a common AWS cause. Usually it means a wrong DNS record or a routing mistake rather than a broken web server.
The origin accepted the request but did not answer within Cloudflare’s read timeout.
Cloudflare documents it as a successful connection where "the origin did not provide an HTTP response before the default 125 seconds Proxy Read Timeout". A long query or a resource-starved server is the usual reason. It is the Cloudflare equivalent of a 504, and the fix is to make the work finish sooner or move it to a background job.
The TLS handshake between Cloudflare and the origin failed.
Cloudflare says it occurs when the handshake with the origin fails and the SSL mode is Full or Full (Strict). A missing or misconfigured certificate at the origin, or a cipher mismatch, will do it. It is about the leg between Cloudflare and your server, not between the browser and Cloudflare.
Cloudflare could not validate the certificate the origin presented.
Cloudflare: "Cloudflare is unable to verify the SSL certificate on your origin server, preventing a secure connection from being established." It needs SSL mode Full (Strict) to appear at all. An expired, self-signed or wrong-hostname certificate at the origin is the cause; Cloudflare offers its own origin certificates for this.
Cloudflare cannot resolve the origin hostname, and the body carries a 1xxx error code.
Cloudflare documents 530 as being returned when it has trouble resolving the origin hostname, so no connection can be attempted. The real detail is in the body, which contains a 1XXX error code such as 1016. Read that number first; the 530 itself only tells you the lookup failed.
No status code matches that. Try a number, or a word such as "gateway" or "cache".
Every status code in the IANA registry, with its official reason phrase, a plain explanation, the defining RFC and a link straight to the code, plus the vendor codes from nginx and Cloudflare that are not in the registry.
On this page
How to use this page#
- Search by number or by words. Type
404to jump to one code, orgateway,cache,rateto find every code whose name or explanation mentions it. The list filters as you type. - Narrow to a class. The
1xxto5xxchips show one class at a time, which is the quickest way to answer "what are all the redirect codes". - Link straight to a code. Every entry has its own anchor, so
/http-status-codes#status-404opens the page at 404 with the entry highlighted. Click the number to put that link in your address bar, ready to paste into an issue or a pull request. - Follow the reference. The citation on the right of each entry links to the exact section of the RFC that defines the code, so you can check the wording yourself rather than trusting a summary.
The page works without JavaScript: every code is in the HTML, and the anchors and highlighting are plain HTML and CSS. The search box and the class chips are the only parts that need scripting.
How HTTP status codes work#
Every HTTP response starts with a three-digit status code between 100 and 599. The first digit puts it in one of five classes, and the last two have no categorising role at all. That first digit is enough on its own: RFC 9110 requires a client to "understand the class of any status code, as indicated by the first digit, and treat an unrecognized status code as being equivalent to the x00 status code of that class", so an unknown 499 is handled as a400 and an unknown 599 as a 500.
- 1xx informational. An interim response; the real one is still coming.
- 2xx successful. The request was received, understood and accepted.
- 3xx redirection. Something more has to happen to finish the request.
- 4xx client error. The request as sent will not work.
- 5xx server error. The server failed or cannot do what was asked.
There are 64 codes in theIANA HTTP Status Code Registry, and most of the ones you meet daily are defined inRFC 9110, section 15. The rest come from smaller specifications: WebDAV, rate limiting, early data, legal blocking. Everything else you see in a log, such as nginx's 499 or Cloudflare's 522, is a vendor invention.
The reason phrase is decoration
"Not Found" in HTTP/1.1 404 Not Found is the reason phrase, and it carries no meaning for software. RFC 9110 says the phrases "are only recommendations -- they can be replaced by local equivalents or left out altogether without affecting the protocol", andRFC 9112makes the grammar optional and tells clients to ignore it, "because it is not a reliable channel for information (it might be translated for a given locale, overwritten by intermediaries, or discarded when the message is forwarded via other versions of HTTP)".
Newer versions of HTTP drop it entirely. HTTP/2 carries the code in a single :statuspseudo-header and defines nothing to hold a phrase (RFC 9113, section 8.3.2). HTTP/3 says so outright: "HTTP/3 does not define a way to carry the version or reason phrase that is included in an HTTP/1.1 status line" (RFC 9114, section 4.3.2). That is why curl -I prints a bare HTTP/2 200, and whyresponse.statusText is an empty string in a browser over HTTP/2 or HTTP/3. Never branch on the phrase; branch on the number.
The codes developers mix up#
301 vs 308, and 302 vs 307 vs 303
All five send the client somewhere else. They differ on whether the move is permanent and whether the method survives.
| Code | Kind | Request method | Use it when |
|---|---|---|---|
| 301 | Permanent | MAY change POST to GET | A URL has moved for good and you accept the historical method rewriting. |
| 308 | Permanent | Preserved | A URL has moved for good and a POST must stay a POST. |
| 302 | Temporary | MAY change POST to GET | The default redirect of most frameworks. Fine for GET traffic. |
| 307 | Temporary | Preserved | A temporary move where the method and body must survive. |
| 303 | Other resource | Changed to GET by design | After a POST, to send the client to a page describing the result. |
The method column is the part people get wrong, and RFC 9110 is precise about it. For 301 and 302 it adds the same note: "For historical reasons, a user agent MAY change the request method from POST to GET for the subsequent request", pointing at 308 and 307 respectively for when that is undesired. For 307 the rule is the opposite: "the user agent MUST NOT change the request method if it performs an automatic redirection to that URI."
The history explains the mess. RFC 9110 records that 301 and 302 were originally defined as method-preserving, that "early user agents split on whether to redirect POST requests as POST ... or as GET", that "prevailing practice eventually converged on changing the method to GET", and that 307 and 308 "were later added to unambiguously indicate method-preserving redirects".
303 is the odd one, and it is not a mistake: changing to GET is its entire purpose. After a POST succeeds, answering 303 sends the browser to a result page with its own URL, so a refresh does not resubmit the form. That is the post/redirect/get pattern.
401 vs 403
401 is about who you are, 403 about what you may do, despite the names suggesting the reverse. A 401 means the request "lacks valid authentication credentials for the target resource", and a server sending one MUST include a WWW-Authenticate header with a challenge. A 403 means the server "understood the request but refuses to fulfill it", and if credentials were sent, it considers them insufficient, so the client should not retry with the same ones.
The practical test: if logging in could fix it, send 401. If the caller is authenticated and still not allowed, send 403. RFC 9110 also allows a third option: a server that wants to hide the existence of a forbidden resource MAY answer 404 instead.
404 vs 410
404 says nothing about whether the absence is temporary. 410 says the resource is gone and "this condition is likely to be permanent". RFC 9110 puts the choice on what the server knows: 410 is preferred "if the origin server knows, presumably through some configurable means, that the condition is likely to be permanent", and if it does not know, "the status code 404 (Not Found) ought to be used instead".
Use 410 for a deliberately retired page, an expired offer or a removed API version, and 404 for everything else. Both are heuristically cacheable, so a CDN can hold on to either.
400 vs 422
400 is for a request the server "cannot or will not process due to something that is perceived to be a client error", with malformed syntax and bad message framing as the RFC's examples. 422 covers the case where the framing and the syntax are fine but the meaning is not: the server "understands the content type of the request content (hence a 415 ... is inappropriate), and the syntax of the request content is correct, but it was unable to process the contained instructions."
So: broken JSON is a 400, valid JSON with a negative quantity is a 422. Plenty of well-known APIs return 400 for both, which is not wrong so much as less specific. RFC 9110 renamed 422 from WebDAV's "Unprocessable Entity" to "Unprocessable Content", so both phrases are in circulation for the same code.
500 vs 502 vs 503 vs 504
- 500 is your own code failing: "an unexpected condition that prevented it from fulfilling the request". The cause is in your logs, never in the response.
- 502 comes from a proxy or gateway that "received an invalid response from an inbound server". The proxy is fine; the thing behind it answered with rubbish or not at all.
- 503 is a healthy server saying not right now, due to "a temporary overload or scheduled maintenance". It can carry
Retry-After. RFC 9110 adds that an overloaded server is not obliged to use it; "some servers might simply refuse the connection". - 504 is a proxy that "did not receive a timely response from an upstream server". Silence rather than a bad answer, which is the whole difference from 502.
A quick triage: 500 means read your application logs. 502 and 504 mean look at the service behind the proxy, one for crashing and one for being slow. 503 usually means something is deliberately shedding load.
200 vs 201 vs 202 vs 204
- 200: it worked, and here is the result in the body.
- 201: it worked and something new exists. Send
Locationpointing at it. - 202: accepted, not done. The RFC calls it "intentionally noncommittal": the work might still be rejected when it runs, and HTTP has no way to tell you later. Point at a status endpoint in the body.
- 204: it worked and there is deliberately nothing to send. The usual answer to a successful DELETE. It "is terminated by the end of the header section; it cannot contain content or trailers", so do not attach a body to one.
304 and conditional requests#
304 is a redirect, in a sense: it points the client at its own cache. The client sends a conditional GET carrying If-None-Match with an ETag, orIf-Modified-Since with a date. If the condition is false, meaning nothing changed, the server answers 304 with no body, and the client reuses what it already has "as if it were the content of a 200 (OK) response".
The server still has to send the header fields that matter for caching:Content-Location, Date, ETag, Vary,Cache-Control and Expires. Leaving out Vary orETag on a 304 is a common bug, because the cache then updates its stored entry with incomplete metadata. And since a 304 ends at the header section, a body on one is a protocol error, not just wasted bytes.
What status codes mean for Google Search#
Google documents how its crawlers handle each code inHTTP status codes and network errors on Search Central. The points that decide how you should answer a crawler:
- 2xx. "Google considers the content for processing (for example, in the case of Google Search, for indexing)", but "an HTTP 2xx (success) status code doesn't guarantee indexing". A 200 that renders an error message can be reported as a soft 404.
- 301 and 308. "Google follows the redirect, and Google systems use the redirect as a strong signal that the redirect target should be processed." 308 is listed as equivalent to 301.
- 302, 303 and 307. The same following, but "a weak signal that the redirect target should be processed". 307 is listed as equivalent to 302. Google adds that although it treats the pairs alike, they are semantically different, so use the right one for other clients.
- 304. "Google crawlers signal the next processing system that the content is the same as last time it was crawled", with no separate effect on indexing.
- 4xx. "Google doesn't use the content from URLs that return 4xx status codes", and "URLs that are already indexed and return a 4xx status code are removed from the index". 404 and 410 are handled the same way here.
- 429 and 5xx. "5xx and 429 server errors prompt Google's crawlers to temporarily slow down with crawling." Indexed URLs are kept for a while and eventually dropped. Google explicitly says not to use 401 and 403 to limit crawl rate, because "the 4xx status codes, except 429, have no effect on crawl rate".
Anything beyond that, such as claims that a particular code carries or destroys "link equity" by some percentage, is not in Google's documentation, so this page does not repeat it.
Seeing the status code yourself#
With curl
# The status code and nothing else
curl -o /dev/null -s -w '%{http_code}\n' https://example.com
200
# The whole response head, without downloading the body
curl -sI https://example.com
HTTP/2 200
content-type: text/html
# Every hop of a redirect chain
curl -sIL https://www.rfc-editor.org/rfc/rfc9110 | grep -i '^HTTP/'
HTTP/2 302
HTTP/2 200
# Where a redirect chain ends up
curl -o /dev/null -sL -w '%{http_code} %{url_effective}\n' https://www.rfc-editor.org/rfc/rfc9110
200 https://www.rfc-editor.org/info/rfc9110/-I sends a HEAD request, so you get the response head without downloading the body. Some servers treat HEAD differently from GET, so if a status looks odd, repeat it with-o /dev/null -s -w '%{http_code}', which sends a real GET and prints just the number. Note that curl -I over HTTP/2 shows no reason phrase, because there is none to show.
In browser dev tools
Open the Network panel before loading the page, and read the Status column. A greyed-out row usually means the response came from cache. Click a request and the Headers tab shows the status line and, for a redirect, the Location header that points at the next hop. Turning on "Preserve log" keeps the chain visible across navigations, which is the only way to see a 301 that the browser has already followed.
In JavaScript
const res = await fetch('/api/thing');
res.status; // 404
res.statusText; // 'Not Found' over HTTP/1.1, '' over HTTP/2 and HTTP/3
res.ok; // true only for 200 to 299
// fetch does not reject on 4xx or 5xx. Check the status yourself.
if (!res.ok) throw new Error(`Request failed: ${res.status}`);Questions people ask#
How many HTTP status codes are there?
64 codes are registered with IANA today, spread over five classes and with large unassigned gaps between them. That count includes 306 and 418, which are reserved and carry no reason phrase, and 104, which is a temporary registration from a draft. Codes like 499 and 522 are common in logs but are not registered.
What is the difference between 401 and 403?
401 means you are not authenticated, or the credentials you sent were rejected, and the response must include a WWW-Authenticate challenge. 403 means the server knows who you are and refuses anyway. Logging in can fix a 401; it cannot fix a 403.
Should I use 301 or 302 for a redirect?
301 if the address has changed for good, 302 if it is temporary. 301 is cacheable and Google treats it as a strong signal, so browsers and crawlers may remember it for a long time; that is exactly what you want for a real move and painful if you sent it by mistake. If the redirect has to preserve a POST, use 308 or 307 instead.
Is 418 I'm a teapot real?
It is real as a reservation, not as a usable code. It comes from RFC 2324, an April Fools' RFC about a coffee pot protocol. RFC 9110 explains that the joke "has been deployed as a joke often enough for the code to be unusable for any future use", so 418 is reserved in the registry, which lists it as "(Unused)". It could be reassigned if the 4xx range ever runs short.
Why do I get a 502 or 504 and not a 500?
Because the error is being reported by something in front of your application: nginx, a load balancer, a CDN. 502 means it got an invalid response from what it forwarded to; 504 means it got no response in time. Your application may never have logged anything, which is why these two send people looking in the wrong place.
What is a 499 error?
It is nginx's log entry for a client that closed the connection before the response was ready, usually a user navigating away or a caller whose own timeout fired first. Nothing is sent to the client, because there is no client left. It is defined in nginx's source asNGX_HTTP_CLIENT_CLOSED_REQUEST, not in any RFC.
Do status codes work the same in HTTP/2 and HTTP/3?
The codes and their meanings are identical; only the framing changes. Both carry the code in a:status pseudo-header instead of a status line, and neither carries a reason phrase. Semantics live in RFC 9110, which is shared by every version.
Can I invent my own status code?
You can, and vendors do, but a client is entitled to treat any unrecognised code as the generic code for its class, so a custom 499 is just a 400 to anything that has not been told otherwise. New codes are meant to go through the registry, as RFC 9110 sets out insection 16.2. Put your own detail in the response body, ideally asRFC 9457 problem details, and keep the status code standard.
Related tools
Percent-encode and decode URLs and query strings, with encodeURIComponent, encodeURI, strict RFC 3986 and form encoding, plus a breakdown of the query parameters.
Encode text or a file to Base64 and decode it back, with correct UTF-8, standard and URL-safe alphabets, optional padding, MIME line wrapping and data: URIs.
Convert a Unix timestamp to a date and back, with the unit detected from the number, any IANA time zone, ISO 8601, RFC 2822, relative time and ISO week, plus the current epoch ticking live.