SiteError.comYour friendly guide to HTTP status codes
Status CodesBlog
  1. Home
  2. Blog
  3. Understanding HTTP 418 I'm a Teapot: The April Fools' Code That Refused to Die

Understanding HTTP 418 I'm a Teapot: The April Fools' Code That Refused to Die

August 24, 20268 min read
4xxClient Error

418 I'm a Teapot is the rare HTTP status code whose entire appeal is that it was never supposed to be taken seriously — and then the internet took it seriously anyway. It started as a joke buried in an April Fools' RFC in 1998, nearly got deleted from major HTTP libraries in 2017, and survived because enough developers pushed back. This post covers where 418 actually comes from, the campaign that kept it alive, what today's HTTP standard says about it, and why — despite all the affection for it — it's the wrong code to reach for when something has genuinely gone wrong.

What Is a 418?

A 418 response tells the client that the server refuses to brew coffee because the server is, in fact, a teapot.

Any attempt to brew coffee with a teapot should result in the error code '418 I'm a teapot'. The resulting entity body MAY be short and stout. — RFC 2324, Section 2.3.2

That's not a paraphrase softened for a blog post — it's the literal text of the specification, published on April 1, 1998, as part of the Hyper Text Coffee Pot Control Protocol (HTCPCP), a joke RFC about controlling coffee pots over HTTP. RFC 2324 says outright that it "does not specify an Internet standard of any kind" and is classified as Informational, not Standards Track. The 418 status code has never, at any point, been a real, load-bearing part of the HTTP specification.

418 was an April Fools' joke from 1998 about the Hyper Text Coffee Pot Control Protocol. It means "I'm a teapot, not a coffee pot!" While it's not a real status code for production use, it's beloved by developers and sometimes used as an easter egg or for testing purposes.

In 2014, a second April Fools' RFC — RFC 7168, published (again) on April 1st — extended HTCPCP to cover networked tea brewing, and reused 418 for tea-incapable pots rather than redefining it. Two jokes, sixteen years apart, both landing on the same day of the year on purpose.

The 2017 Campaign to Save It

In August 2017, Mark Nottingham — at the time chair of the IETF's HTTP working group — argued that since 418 was never part of a real standard, it should be stripped out of Node.js, and suggested Go, Python's Requests, and ASP.NET follow suit. The reasoning was defensible: 418 doesn't appear in RFC 7231 (the HTTP spec of the time), so keeping it around in production HTTP libraries was arguably carrying a joke where it didn't belong.

The response was immediate. A then-15-year-old developer, Shane Brunswick, put up save418.com, the post went viral on Reddit, and #save418 trended as a hashtag. Node.js, Go, Python's Requests, and ASP.NET's HttpAbstractions library all ended up keeping 418 rather than removing it. The episode is a useful reminder that "not in the spec" and "not real" aren't the same thing once enough tooling and enough developers have built habits — and even inside-joke Easter eggs — around a status code.

Why RFC 9110 Still Won't Define It

Here's the detail that resolves the tension between "beloved by developers" and "not a real standard": RFC 9110 — the current HTTP semantics specification, published in 2022 — does reserve a slot for 418 in its status code registry, but the entry is titled "418 (Unused)" (Section 15.5.19). RFC 9110 doesn't carry forward the teapot semantics from RFC 2324, and it doesn't repurpose the number for something else either — it deliberately leaves it defined-as-undefined. IANA's own status code registry lists 418 the same way: "(Unused)," referencing that section.

So the honest way to describe where 418 stands: it isn't erased, and it isn't standardized. It's a number the HTTP registry has agreed to leave alone, out of respect for how deeply it's embedded in developer culture, without ever promoting it to a real, defined status.

418 vs Real Error Codes

418 doesn't have a natural confusable pair the way 401/403 or 404/410 do — its whole identity is that it sits outside the normal 4xx contract. What's worth comparing it against is what a real 4xx code promises, since that's exactly what 418 doesn't:

CodeMeaningStandards status
400 Bad RequestThe request is malformedStandards Track, RFC 9110
404 Not FoundThe resource doesn't exist (or the server won't say)Standards Track, RFC 9110
451 Unavailable For Legal ReasonsAccess is blocked by legal demandStandards Track, RFC 7725
418 I'm a TeapotA teapot was asked to brew coffeeInformational, April Fools' RFC 2324 — reserved as "(Unused)" in RFC 9110

Every other row in that table is a code you can build real error-handling logic around, with a defined meaning a client is expected to act on. 418 is the one row where the correct client behavior, per the spec that introduced it, is to laugh.

Legitimate(ish) Uses

The situations where teams actually reach for 418, with the understanding that none of them are "real errors":

  1. The server is, narratively, a teapot. Literal Easter eggs — an endpoint that exists purely to return the joke, often as a nod to the RFC itself.
  2. Testing and fixtures. Because 418 is instantly recognizable and guaranteed not to collide with a real error condition in your application, it's occasionally used as an unambiguous placeholder status in test suites or mock servers.
  3. Developer culture, not user-facing behavior. Teams sometimes wire it into internal tools or April Fools' releases — always as a deliberate wink, never as the response to an actual failure a real client needs to handle correctly.

Returning 418 (Responsibly)

Express / Node.js

// An intentional easter egg — not a real error path
app.get("/brew-coffee", (_req, res) => {
  res.status(418).json({
    error: "im_a_teapot",
    message: "I'm a teapot, short and stout. Try /brew-tea instead.",
  });
});

Next.js App Router

// app/brew-coffee/route.ts
export async function GET() {
  return Response.json(
    { error: "im_a_teapot", message: "I'm a teapot, short and stout." },
    { status: 418 },
  );
}

NGINX

# A dedicated, clearly-labeled easter egg route — not wired into real error handling
location = /brew-coffee {
    default_type application/json;
    return 418 "{\"error\":\"im_a_teapot\",\"message\":\"I am a teapot, short and stout.\"}";
}

REST API JSON body

HTTP/1.1 418 I'm a teapot
Content-Type: application/json
 
{"error": "im_a_teapot", "message": "I'm a teapot, short and stout."}

Keep it isolated to a route that's obviously a joke. The moment 418 shows up on an endpoint a real client is expected to handle programmatically, it's stopped being a wink and started being a bug.

Common Pitfalls

  1. Using 418 for a genuine error condition. Nothing about 418 communicates anything a real client can act on — reaching for it instead of 400, 404, or 503 for an actual failure just confuses whatever's consuming your API.
  2. Assuming 418 is part of the official HTTP standard because it "feels" standardized. It's from an Informational April Fools' RFC and is explicitly marked "(Unused)" in RFC 9110 — it has never been Standards Track.
  3. Stripping 418 support from a library without checking for real dependents. The 2017 near-removal showed that plenty of tooling, tests, and easter eggs quietly depend on 418 staying available, even though it's a joke — removing it isn't as harmless as "it's not a real code" makes it sound.
  4. Treating "(Unused)" in RFC 9110 as "available for reuse." IANA still lists 418 in the registry — it's reserved, not open for a project to redefine with new, serious semantics.
  5. Putting 418 in front of a client that doesn't expect it. Some HTTP clients, proxies, or monitoring tools treat an unrecognized or joke status code oddly (e.g., logging it as an anomaly) — know your audience before wiring 418 into anything beyond a clearly-labeled easter egg.

Wrapping Up

418 is proof that a joke can outlive the platform it joked about, provided enough people decide it's worth keeping. The rules of thumb:

  • 418 means a teapot was asked to brew coffee — literally, per RFC 2324, an April Fools' RFC from 1998
  • It has never been Standards Track, and RFC 9110 keeps it reserved as "(Unused)" rather than defining or repurposing it
  • The 2017 #save418 campaign is why it's still supported in Node.js, Go, Python's Requests, and ASP.NET today
  • Use it for easter eggs and clearly-isolated jokes only — never as a real error response a client is expected to handle

For more, see our page on 418 I'm a Teapot, and our posts on 400 Bad Request and 451 Unavailable For Legal Reasons for what a genuinely standardized 4xx code looks like by comparison.

Full Reference

418 I'm a Teapot

The server refuses the attempt to brew coffee with a teapot. An April Fools' joke from 1998.

Related Status Codes

🤨400Bad Request🔐401Unauthorized💳402Payment Required🚫403Forbidden🔍404Not Found🙅405Method Not Allowed🍽️406Not Acceptable🎫407Proxy Authentication Required⏰408Request Timeout⚔️409Conflict👻410Gone📏411Length Required❌412Precondition Failed📦413Payload Too Large📜414URI Too Long📼415Unsupported Media Type📖416Range Not Satisfiable😞417Expectation Failed🫖418I'm a Teapot🚪421Misdirected Request🤔422Unprocessable Entity🔒423Locked🎯424Failed Dependency⏰425Too Early⬆️426Upgrade Required🔑428Precondition Required🚦429Too Many Requests📋431Request Header Fields Too Large⚖️451Unavailable For Legal Reasons
Back to Blog

Popular Status Codes

  • 200 OK
  • 301 Moved Permanently
  • 302 Found
  • 400 Bad Request
  • 401 Unauthorized
  • 403 Forbidden
  • 404 Not Found
  • 500 Internal Server Error
  • 502 Bad Gateway
  • 503 Service Unavailable

Compare Codes

  • 401 vs 403
  • 301 vs 302
  • 404 vs 410
  • 500 vs 502
  • Compare any codes →

Categories

  • Informational
  • Success
  • Redirection
  • Client Error
  • Server Error
  • NGINX
  • Cloudflare
  • AWS ELB
  • Microsoft IIS

Tools

  • Cheat Sheet
  • Status Code Quiz
  • URL Checker
  • API Playground
  • Blog

© 2026 SiteError.com. All rights reserved.