Every page your browser opens arrives with a three-digit number attached that you never see. It is the only thing on the web that machines read and people do not, and about ten of them are worth knowing.
October 2026
Error responses are supplied in human readable text in HTML syntax.
Tim Berners-Lee, The HTTP Protocol As Implemented In W3, 1991
When a browser asks a server for a page, the first thing that comes back is not the page. It is a line with a number on it. The browser reads that number, decides what to do — show this, go somewhere else, use the copy it already has, give up — and only then does anything appear on your screen. Search engines read the same number. So do link checkers, archives, and anything else that visits your site without eyes.
Get the number wrong and everything looks fine to you, while every machine that visits draws the wrong conclusion. That is the whole reason this is worth twenty minutes.
1991: a web with no way to say no
The first version of the protocol, the one Berners-Lee wrote at CERN and which we now call HTTP/0.9, had no status codes at all. It is a short document and you can still read it. The server received a request and sent back a stream of HTML. That was the entire conversation.
Which leaves an obvious problem, and the specification states it plainly: error responses are supplied in human readable text in HTML syntax, and there is no way to distinguish an error response from a satisfactory one except by the content of the text. In other words, in 1991 a program could not tell whether it had received a page or an apology. Only a person reading it could.
Everything in this essay exists to fix that one sentence.
Where the numbers came from, and who chose them
Short answer: Berners-Lee picked the first set, at CERN, in 1992 — but he did not invent the scheme, and nobody at CERN owns it now.
The scheme was already old. Three-digit replies in which the first digit carries the meaning were how internet protocols had answered for years before the web. File transfer had used them since the early eighties — a positive completion in the two hundreds, a transient failure in the four hundreds, a permanent one in the five hundreds. Mail transfer worked the same way. When the web needed status codes, the obvious thing to do was the thing everybody already did, and that is what happened.
The first list is from 1992, in a document on the W3C’s server called simply “Status codes in HTTP”. That is where 404 appears, with a definition that has barely changed since: the server has not found anything matching the URI given. The page is still online, with a note at the top warning that it is no longer accurate.
And then it stopped being his. When HTTP went to the IETF, the codes went with it: HTTP/1.0 was written up in 1996 by Berners-Lee together with Roy Fielding and Henrik Frystyk Nielsen, HTTP/1.1 followed, and the current specification is RFC 9110 from 2022. New codes still arrive the same way, by proposal and review: 429, for a client asking too often, was added in 2012; 451, for a page withheld for legal reasons, in 2016. That last number is a reference to Fahrenheit 451, which tells you something about the people who write these documents.
So the honest answer to “did Berners-Lee and CERN decide the numbers” is: he chose the first dozen, from a convention he inherited, and the web has been adding to them by committee ever since. There was no room 404, and there was no moment of invention either.
The five classes, which is most of what you need
The specification is unusually generous here. It says in one sentence that the first digit defines the class of response and that the last two digits have no categorising role at all. Learn five things and you can read a code you have never seen before.
- 1xx — hold on. Informational, rare, and you will almost never meet one.
- 2xx — yes. It worked.
- 3xx — look elsewhere. The thing is somewhere else, or you already have it.
- 4xx — your request was wrong. Something about what was asked for does not work: the address, the permission, the frequency.
- 5xx — our end broke. The request was fine; the server failed to answer it.
That one distinction between four hundred and five hundred saves more time than any other piece of knowledge here. A 4xx is a conversation about an address. A 5xx is a conversation with your host.
And then the ones you actually meet, which is a shorter list than the specifications suggest:
The ten worth knowing
| Code | What it means | When you want it |
|---|---|---|
200 | It worked. Here is the page. | The normal answer. Also the wrong answer for a “not found” page — see below. |
301 | Moved permanently. | The thing exists at a new address and is not coming back. One old address to the one page that replaced it. |
302 | Moved temporarily. | Almost never what you mean. It tells search engines to keep the old address. Use it only while something is genuinely away for a while. |
304 | Not modified. | You do not send this by hand; your server does, to say “you already have this”. It is why a second visit is fast. |
403 | Forbidden. | The thing exists but you may not have it. Fine for an admin area; a poor choice when you would rather not confirm that something exists at all. |
404 | Not found. | The address does not match anything, or you are unwilling to say whether it does. The honest answer when you do not know. |
410 | Gone. | You removed it on purpose and it is not coming back. Search engines drop it faster than a 404, and it is simply more truthful. |
429 | Too many requests. | A client is asking too often. Worth knowing when a scraper is flattening your site — it is the polite way to say slow down. |
451 | Unavailable for legal reasons. | Something is withheld on legal grounds. Rare, and worth using over a vague 403 when it applies, because it is honest about why. |
500 | Server error. | Something broke at your end. A blank white page is usually this. Your error log has the reason; the visitor should not. |
503 | Service unavailable. | Temporarily down, by choice or by load. Send it during maintenance, with a Retry-After header, so search engines come back instead of dropping you. |
The two mistakes that cost real money
Answering 200 when you mean 404. A page that says “not found” but returns the success code is a soft 404. A person sees an error. Every machine sees a perfectly good page, so it gets indexed, archived and reported as a healthy link. You end up with hundreds of indexed copies of your apology, and a search engine that believes your site is full of pages about nothing. Test it with an invented address and look at the status, not at the screen.
Using 302 when you mean 301. They look identical to the visitor, and opposite to everything else. A permanent redirect says “transfer what you know about the old address to the new one”. A temporary one says “keep the old one, I will be back”. Sites have been moved in their entirety with 302s and spent a year wondering why the move never took.
There is a third, which has its own essay: redirecting every unknown address to the home page. It is neither a redirect nor a 404; it is an evasion, and it gets read as a soft 404 anyway. That belongs on the 404 page instead.
And 418
If you go looking you will find code 418, “I’m a teapot”. It comes from the Hyper Text Coffee Pot Control Protocol, published as an RFC on the first of April 1998, in which a teapot asked to brew coffee must refuse. It was a joke, written properly, in the format of a real standard.
It has outlived most serious proposals. Attempts to reclaim the number for real use have been beaten back by developers who argued, with some passion, that the web should keep one joke in it. Several frameworks implement it. I mention it because it is the single best demonstration of the point above: these numbers are not handed down from anywhere. They are written by people, argued over in public, and occasionally those people are being funny.
Where this leaves you
You will not need most of this most days. What you need is the reflex: when something is wrong, look at the number before you look at the page, because the number is what everything other than you is reading.
And when you retire an address, pick deliberately between the three answers that mean something — moved, gone, or never existed. Each is true in a different situation, and picking the wrong one is how a site slowly loses the links other people have been kind enough to make to it.
Read the originals
The second one takes two minutes and is the most charming document on this list: the entire protocol, from before it had any way to report a problem.
- RFC 9110: HTTP Semantics — IETF, 2022. The current specification. Every code, with its exact meaning, in the only place where that meaning is actually defined.
- Tim Berners-Lee, The HTTP Protocol As Implemented In W3 — 1991. The original, with no status codes at all, and the sentence admitting that a program cannot tell an error from a page.
- Status codes in HTTP — W3C, 1992. The first list, where 404 appears. Still online, still warning you that it is out of date.
- Hypertext Transfer Protocol — HTTP/1.0 — for the sentence that explains the whole scheme: the first digit defines the class, the last two mean nothing.
- RFC 6585 (2012) and RFC 7725 (2016) — where 429 and 451 were added, if you want to see how a new code actually arrives.
- RFC 2324: Hyper Text Coffee Pot Control Protocol — 1 April 1998. The teapot.