Skip to content
OneKitly

HTTP Status Codes Explained: The Ones That Actually Get Confused

Published 4/29/2026 · 8 min read · Developer tools

Daniel Okonkwo

Daniel OkonkwoFront-end developer and tech writer at OneKitly

Web performance · File formats

Checked against 2 sources

View profile
In short

The first digit is the part every client, cache and crawler reads: 1xx informational, 2xx success, 3xx redirect, 4xx the request was at fault, 5xx the server was. Within those, the distinctions that change behaviour are these. 308 is 301 with a guarantee that the method and body survive the redirect, and 307 is 302 with the same guarantee — older clients turn a redirected POST into a GET on 301 and 302, which is exactly why 307 and 308 exist. 401 means the request carried no valid credentials and must come with a WWW-Authenticate header; 403 means the credentials were fine and the action is still refused, so logging in again will not help. 404 says there is nothing here without committing to why; 410 says the resource was deliberately removed and is not coming back, and is cacheable by default. On 429 and 503, Retry-After is an estimate the server publishes as a number of seconds or an HTTP date — it is guidance for well-behaved clients, not a promise that the service returns on time.

301 against 308, 302 against 307, 401 against 403, 404 against 410 — plus what Retry-After on a 429 or a 503 actually promises. The pairs where picking the wrong code changes behaviour, not just wording.

The first digit is the only part some clients read

RFC 9110 requires a client to understand the class of a status code even when it does not recognise the code itself, and to treat anything unfamiliar as the x00 of its class. A client that has never heard of 451 handles it as a 400; an unknown 599 is handled as a 500. That rule is what makes the space extensible, and it also means the class carries almost all of the behaviour: caches decide storability from it, proxies decide retries from it, and crawlers decide indexing from it, mostly before anything in your response body is parsed.

The practical consequence is that returning 200 with an error described in the body puts a failure somewhere nothing else can see it. Your uptime check reports green, your CDN caches the error page, and a search engine indexes it as a real document. This is the soft 404 problem in general form, and it is worth auditing for, because the fix is a one-line change to a status code rather than anything architectural.

Redirects: which ones keep your POST

The four-code redirect grid is really two questions crossed: permanent or temporary, and does the method survive. 301 and 308 are permanent, 302 and 307 are temporary; 307 and 308 are the two that forbid the client from changing the request. MDN is blunt about why the newer pair exists: 301 already required the method and body to stay unchanged, but that requirement was incorrectly handled by older clients, which switched to GET. Nobody could fix the installed base, so two new codes were minted with the guarantee written into their definition.

So the choice follows from the traffic. For a page that only ever receives GET, 301 is fine and is what search engines are most used to. For an API path, a form target or anything that can receive POST, PUT or DELETE, use 308 and the request arrives intact. One caution about permanence: browsers cache a 301 aggressively and some keep it far longer than you expect, so a 301 issued during an experiment can outlive the experiment on machines you have no access to. Ship 302 or 307 while you are still deciding.

The errors most often returned wrong

401 and 403 are the pair that costs the most support time. 401 means the request lacked valid authentication credentials, and MDN notes that it is sent with a WWW-Authenticate header describing the scheme the server expects — it is an invitation to try again with credentials. 403 is the opposite situation: the credentials are perfectly valid, and the client still does not have permission for this action. Returning 401 to a signed-in user tells their client to re-authenticate, which will produce exactly the same refusal, and tells the user that their login is broken when it is not.

404 and 410 differ only in confidence, and that is the point. MDN's guidance is explicit: if the server owner does not know whether the condition is temporary or permanent, use 404. Use 410 when you removed the thing on purpose and it is not coming back — it is cacheable by default and tells crawlers not to keep asking. Retry-After, meanwhile, is a header that carries either a delay in seconds or an HTTP date; on a 503 it estimates how long the service will be unavailable and on a 429 it says how long to wait before a new request. It is guidance, not a contract, and MDN notes that support across clients is uneven — but Googlebot honours it, which alone makes it worth setting during planned maintenance.

The codes worth getting right, and what each one commits you to
CodeNameWhat it commits you toWhere it goes wrong
200OKThe request succeeded and the body is the resultReturned with an error message inside the body, which hides the failure from caches, monitoring and crawlers
301Moved PermanentlyThis URL is replaced for good; update your linksUsed while still deciding — browsers cache it hard, and older clients turn a redirected POST into a GET
302FoundGo here for now; keep using the original URLUsed for a permanent move, so the old URL keeps absorbing the ranking signals
304Not ModifiedYour cached copy is still valid; there is no bodySent outside a conditional request, or sent with a body that clients are entitled to discard
307Temporary RedirectLike 302, but the method and body must not be changedRarely reached for, so temporary redirects silently break POST-based flows
308Permanent RedirectLike 301, but the method and body must not be changedOverlooked for API endpoints, where a 301 quietly downgrades a POST to a GET
401UnauthorizedNo valid credentials were presented; a WWW-Authenticate header says what is expectedReturned to a user who is already signed in but lacks the right — that case is 403
403ForbiddenThe identity is accepted and the action is still refusedUsed as a catch-all, which invites clients to retry authentication that will never help
404Not FoundThere is nothing at this URL, and the server does not say whether that is permanentReplaced by a friendly page served with 200, the soft 404 that keeps dead URLs indexed
410GoneDeliberately removed and not coming back; cacheable by defaultAlmost never used, even when the removal was intentional and 404 understates it
429Too Many RequestsA rate limit was hit; Retry-After says how long to wait before a new requestSent without Retry-After, leaving clients to guess and hammer the endpoint
500Internal Server ErrorThe server failed and has nothing more specific to sayReturned for a bad request from the client, which belongs in the 400 range instead
502Bad GatewayA proxy received an invalid response from the server it forwarded toDebugged in the application, when the fault sits between the proxy and the upstream
503Service UnavailableTemporarily unable to serve; Retry-After estimates how long the outage will lastReplaced by a 500 during planned maintenance, so crawlers treat the outage as a real failure
HTTP Status Code ReferenceSearch and browse every standard HTTP status code by class, with its name and a one-line description.Try the tool

Frequently asked questions

Should a site migration use 301 or 308?
For pages that are only ever fetched with GET, 301 is the safe default and the one every crawler and proxy has handled for decades. Reach for 308 on anything that can receive a POST, PUT or DELETE — form endpoints, API routes, webhook receivers — because that is where a client silently downgrading the method turns a redirect into a lost request body. There is no reason you cannot use both on the same migration, chosen per route.
What should an API return when validation fails?
Use 400 Bad Request when the request itself is malformed and the server cannot parse it — broken JSON, a missing required header. Use 422 Unprocessable Content when the syntax is fine but the content breaks your rules, such as a well-formed body with an end date before its start date. What you should not return is 500, which blames the server for a client mistake and pollutes your error budget, or 200 with the problem described in the body, which hides the failure from every layer between you and the caller.
Do 404s hurt search rankings?
A 404 is a valid, honest answer and a normal part of any site that has existed for a while; a page that no longer exists should say so. The damage comes from the substitutes. A soft 404 — a friendly page served with status 200 — keeps dead URLs in the index and spends crawl budget on nothing. A blanket redirect of every missing page to the homepage is the same mistake wearing a 301. If the removal was deliberate and permanent, 410 states it plainly.

Articles you may find interesting

All guides
How-toHow to Write a Cron Expression: Five Fields and the OR Rule Nobody MentionsMinute, hour, day of month, month, day of week. The traps are that a step is a stride through a range and not an interval, and that the two day fields are combined with OR — so 0 0 1 * 1 fires on the 1st and on every Monday.How-toHow to Write a robots.txt: Directives, Matching, and What It Cannot HideFour directives, two wildcards, one file at the host root. It is a crawl instruction and nothing more — it does not remove a page from search results, it does not restrict access, and it publishes every path you list in it.ExplainerHow Unix File Permissions Work: Reading 755 Without GuessingRead is 4, write is 2, execute is 1, and each of the three digits describes a different party. The part most explanations get wrong is what the execute bit does on a directory — it grants traversal, not the right to run anything.ComparisoncamelCase, snake_case, kebab-case: Which One, and Why You Rarely Get to ChooseThe conventions are not taste. A hyphen is the minus operator, so kebab-case cannot be an identifier in most languages - which is exactly why CSS and URLs use it. Plus the acronym round-trip that silently corrupts names, and the rule that fixes it.ExplainerSemicolon, Tab, Pipe: Choosing a Delimiter That Survives the TripWhy the reader's language decides the delimiter, what the converter does to the quoting when you switch, what the sep= first line really is, and the count of quoted cells on the same export written five ways.How-toRegex Basics: A Beginner's GuideA regular expression is a pattern for matching text. Here are the building blocks — character classes, quantifiers and anchors — with a worked example.

Related tools

Sources

Spotted a mistake in this article?