HTTP Status Codes

The distinctions that cause real bugs

Status code mistakes are rarely about obscure codes. They are about the few pairs that look interchangeable and are not: 301 against 302, 401 against 403, 404 against 410, and any endpoint that answers 200 while describing a failure in the body. Each entry below gives the specification meaning and the case it is for.

Redirects: two separate questions

Permanence tells caches and search engines whether to replace the stored URL. Method preservation tells the client whether the follow-up request may be rewritten as a GET.

CodePermanenceMethod on follow-up
301 Moved PermanentlyPermanentMay be rewritten to GET
302 FoundTemporaryMay be rewritten to GET
303 See OtherTemporaryFollow-up is a GET
307 Temporary RedirectTemporaryPreserved
308 Permanent RedirectPermanentPreserved

Google documents 301 and 308 as permanent redirects and indexes the target; 302, 303 and 307 are temporary, and the original URL stays the one indexed. The method column is why a relocated API route wants 307 or 308: on 301 and 302 a user agent is permitted, for historical reasons, to turn a POST into a GET, and browsers do, so the target sees a bodyless request. Not every 3xx is a redirect either — 304 Not Modified is a cache validation reply and carries no Location.

Authentication, refusal, removal

  • 401 — the request lacked valid authentication credentials for the resource. The response must include a WWW-Authenticate header naming the challenge scheme. Right answer for a missing or expired token.
  • 403 — the server understood the request and refuses to authorize it. Repeating it with the same credentials changes nothing. Usually authenticated-but-not-permitted, and also correct where identity is irrelevant, such as a blocked address.
  • 404 — no current representation is known at this URL. Covers typos, guesses and things that never existed; also a valid way to hide whether a protected resource exists.
  • 410 — the resource was here and was deliberately removed, with no forwarding address known.

What each class commits you to

1xx informational, an interim reply before the real one. 2xx the request succeeded. 3xx further action is needed, usually at another URL. 4xx the client side is at fault: malformed, unauthenticated, refused, or over a limit. 5xx the request may have been perfectly valid and the server failed anyway. Proxies, retry logic and monitoring branch on that first digit before reading anything else, so the class matters more than the choice between two neighbours inside it. 429 sits in 4xx even though the individual request was well formed; its spec permits rather than requires Retry-After, but without it a client can only guess.

Share this tool with friends

Free to use, no sign-up, works on any phone.

Frequently Asked Questions

What is the difference between a 301 and a 302 redirect?

301 says the resource has moved permanently and the new URL should replace the old one; 302 says the move is temporary, so the original URL stays the one search engines keep indexed. Leave a 302 on a permanent move and you keep pointing crawlers at the old address. Google has indicated that a long-lived 302 may eventually be read as permanent, but that is not something to design around. Neither code is safe for a moved form or API route: on both, a user agent is permitted for historical reasons to turn a POST follow-up into a GET, and browsers do exactly that.

When should I use 308 instead of 301?

Use 308 when the request method must survive the redirect. RFC 7538 gives 308 the same permanent meaning as 301 but forbids the client from rewriting the follow-up request, so a POST, PUT or DELETE arrives intact with its body. For ordinary GET page moves the two behave the same, and Google documents both as permanent redirects. Every current browser understands 308; only long-obsolete clients that predate it are a concern.

Should an API return 401 or 403 for a logged-out user?

401, because the caller is unauthenticated rather than forbidden. 401 means the request lacked valid credentials for that resource, and the response must include a WWW-Authenticate header naming the challenge scheme. 403 means the server understood the request and refuses to authorize it, so retrying with the same credentials is pointless; it fits an authenticated user without the right permission, and also cases where identity is irrelevant, such as a blocked address. Sending 403 to a logged-out user tells the client there is no point signing in.

Is 410 better than 404 for a page I deleted?

410 is the more accurate code when you removed the page on purpose and it is not coming back: it states that the resource was here and has gone, with no forwarding address known. 404 only says nothing is known at that URL, which also covers typos and URLs that never existed. Google has said it handles the two almost identically, so choose 410 for semantic honesty rather than for a ranking effect, and stay on 404 if you might restore or move the content later.

Why is returning 200 with an error message in the body wrong?

Because everything between your code and the caller treats 200 as success. It is cacheable by default, so a failed response can be stored and replayed; retry and circuit-breaker logic never fires; uptime monitoring reports the service as healthy; and any generic client has to parse the body to discover that something broke. Return the status that matches the failure and keep the human-readable detail in the body.

What should a 429 Too Many Requests response include?

Ideally a Retry-After header, so the caller waits a known interval instead of backing off blindly. The 429 specification permits Retry-After rather than requiring it, but omitting it leaves clients guessing. Its value is either a number of seconds or an HTTP-date. The body should say which limit was hit, since an application usually has several. Retry-After is also valid on 503 when a server is temporarily unavailable and you know roughly when it will return.

Everything on this page runs inside your own browser. Nothing you type or upload is sent to a server, so your data never leaves your device.