Ошибка 418 «I'm a teapot» — «я чайник» — единственный код ответа HTTP, который появился как первоапрельская шутка. Он описан в RFC 2324 про управление кофейниками, а в действующем стандарте HTTP значится как неиспользуемый. Тем не менее код живёт: его знают библиотеки и программное обеспечение серверов, его отдают сайты и сервисы в интернете, и он может выкинуть страницу из поиска. В этой статье — откуда он взялся, как ведут себя разные реализации и что делать, если сайт ответил 418.
Мы собрали стенд из nginx 1.31, Apache 2.4.68, PHP 8.3, Node.js 20, Python 3.11, Chromium 149 и Firefox 151 и проверили, что каждый делает с кодом 418. Главная находка: PHP под Apache вместо 418 отдаёт клиенту 500, и это видно только по ответу, а не по коду программы.
Что означает код 418
Код появился в 1998 году, 1 апреля, в RFC 2324 «Hyper Text Coffee Pot Control Protocol» — протоколе управления кофейниками HTCPCP. Автор — Ларри Мазинтер. Документ информационный, и в нём прямо сказано, что он не задаёт никакого стандарта. Раздел 2.3.2 целиком:
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.
Перевод: любая попытка сварить кофе в чайнике должна заканчиваться ошибкой «418 I'm a teapot». Тело ответа МОЖЕТ быть «маленьким и толстеньким» — отсылка к детской песенке «I'm a little teapot, short and stout».
RFC 2324 высмеивал то, как HTTP тогда пытались расширять под что угодно. Через 16 лет, тоже 1 апреля, вышло продолжение — RFC 7168 «HTCPCP-TEA», уже про чай. В нём уточнено: чайник, который не умеет варить кофе, может ответить 503 — кофе временно нет, — или 418, чтобы сказать, что он чайник навсегда.
Ни один из этих документов не относится к самому HTTP, и приготовление кофе по сети так и осталось шуткой. Протокол HTCPCP — отдельный, шуточный, со своими методами вроде BREW и WHEN.
Как устроен протокол кофейников
Шутка в RFC 2324 написана всерьёз, языком настоящих стандартов, и в этом её соль. HTCPCP «построен поверх HTTP», потому что «HTTP везде», а значит хорош, а раз хорош — на нём и надо варить кофе. Кофейники адресуются собственной схемой coffee:, причём автор приводит её написание на двух десятках языков.
Протокол добавляет к HTTP методы:
- BREW — сварить кофе. POST тоже принимается, но объявлен устаревшим для действий: «POST может оказаться торговой маркой кофе»;
- GET — получить кофе. Автор оговаривает, что данные большинства кофейных адресов «не содержат кофеина»;
- PROPFIND — узнать свойства сваренного напитка;
- WHEN — сказать «хватит», когда молока налили достаточно.
Есть и новый заголовок Accept-Additions: в нём клиент перечисляет добавки — сливки, обезжиренное молоко, ванильный или миндальный сироп, виски, ром. Если оператор кофейника не может выполнить заказ, сервер отвечает 406 Not Acceptable и прикладывает список доступных добавок. Варианта без кофеина нет, и это тоже оговорено: «What's the point?» — «А смысл?».
На этом фоне 418 — последний штрих: если запрос на кофе пришёл чайнику, он честно отвечает, кто он. В RFC 7168 к этому добавились тип данных message/teapot и сорта чая в заголовке Accept-Additions.
Что говорит стандарт HTTP
В действующем стандарте HTTP, RFC 9110 от 2022 года, у кода 418 есть свой раздел 15.5.19 с заголовком «418 (Unused)»:
[RFC2324] was an April 1 RFC that lampooned the various ways HTTP was abused; one such abuse was the definition of an application-specific 418 status code, which has been deployed as a joke often enough for the code to be unusable for any future use.
Перевод: RFC 2324 был первоапрельским документом, который высмеивал злоупотребления HTTP. Одно из них — придуманный для своего приложения код 418, который так часто внедряли ради шутки, что для будущего он стал непригоден.
Дальше сказано, что код 418 зарезервирован в реестре IANA и сейчас не может быть назначен никакому приложению. Если когда-нибудь закончатся свободные коды 4xx, его можно будет переназначить. В реестре IANA строка выглядит так: «418 — (Unused) — RFC 9110, Section 15.5.19».
Так шутка получила место в стандарте: код не значит ничего, но использовать его для серьёзной цели нельзя.
Почему 418 не удалили
В августе 2017 года Марк Ноттингем, председатель рабочей группы HTTP в IETF, открыл задачи в репозиториях Node.js и Go: «Please consider removing support for 418». Его довод: HTCPCP — не HTTP даже по собственному определению, а поддержка 418 в популярных библиотеках уже мешает отдать код под настоящую задачу.
Сообщество восприняло это как покушение на традицию, и код отстояли. В Node.js задачу закрыли в том же месяце, в Go — в марте 2018 года. Сейчас в исходном коде Go константа выглядит так:
StatusTeapot = 418 // RFC 9110, 15.5.19 (Unused)
Код оставили, но ссылку поменяли на раздел стандарта, где он назван неиспользуемым. Это компромисс, на котором и записан RFC 9110: 418 зарезервирован, чтобы старые шутки не сломались, если код когда-нибудь назначат заново.
Где 418 среди кодов HTTP
Статусный код — трёхзначное число в первой строке ответа сервера. По нему браузер, поисковый робот и другие системы понимают, чем закончился запрос, ещё до того, как прочитают тело ответа. Первая цифра определяет класс:
- 1xx — информационные. Сервер получил начало запроса, и клиент может продолжать передачу. Обычно пользователю они не видны.
- 2xx — успешные. Запрос принят и выполнен: 200 OK — запрашиваемый ресурс найден и отдан, 204 — выполнено, но тела в ответе нет.
- 3xx — перенаправления. Ресурс находится по другому адресу, который указывается в заголовке Location: 301 — навсегда, 302 — временно. Если перенаправления ведут по кругу, браузер обрывает бесконечный цикл ошибкой ERR_TOO_MANY_REDIRECTS.
- 4xx — ошибки клиента. Запрос нельзя выполнить по причине на стороне того, кто его отправил: неверный адрес, нет авторизации, слишком много запросов.
- 5xx — ошибки сервера. Запрос корректный, но сервер не смог его обработать или завершить: упало приложение, не ответил сервер за прокси, сайт перегружен.
418 формально попадает в группу 4xx. Вот как выглядит весь класс по RFC 9110 и соседним документам:
| Код | Название | Что означает |
|---|---|---|
| 400 | Bad Request | запрос составлен некорректно, сервер не может его разобрать |
| 401 | Unauthorized | требуется авторизация: войти или передать ключ доступа |
| 402 | Payment Required | зарезервирован на будущее, общего значения нет |
| 403 | Forbidden | сервер понял запрос, но доступ запрещён |
| 404 | Not Found | запрашиваемый ресурс по этому адресу не существует |
| 405 | Method Not Allowed | метод запроса не разрешён для адреса |
| 406 | Not Acceptable | нет ответа в формате, который просит клиент |
| 407 | Proxy Authentication Required | авторизация требуется на прокси |
| 408 | Request Timeout | сервер не дождался запроса и закрыл соединение |
| 409 | Conflict | запрос конфликтует с текущим состоянием ресурса |
| 410 | Gone | ресурс удалён навсегда |
| 411 | Length Required | в запросе нет заголовка Content-Length |
| 412 | Precondition Failed | не выполнено условие из заголовков запроса |
| 413 | Content Too Large | тело запроса больше, чем сервер готов принять |
| 414 | URI Too Long | адрес слишком длинный |
| 415 | Unsupported Media Type | формат тела не поддерживается |
| 416 | Range Not Satisfiable | запрошенный диапазон байтов вне файла |
| 417 | Expectation Failed | сервер не может выполнить ожидания из заголовка Expect |
| 418 | (Unused) | зарезервирован, значения нет |
| 421 | Misdirected Request | запрос пришёл на сервер, который не отвечает за этот адрес |
| 422 | Unprocessable Content | запрос понятен, но данные в нём неверны |
| 426 | Upgrade Required | сервер требует перейти на другой протокол |
| 429 | Too Many Requests | превышен лимит запросов за промежуток времени |
| 451 | Unavailable For Legal Reasons | ресурс недоступен по требованию закона |
Для большинства этих кодов у нас есть отдельные разборы со стендом: что именно видит пользователь, что пишется в журнал и как исправить — например, 400, 401, 408, 410 и 413.
Коды 419 и 420 не назначены вовсе. Интересно, что 402 тоже зарезервирован «на будущее», но по серьёзной причине, а 418 — потому что его уже заняла шутка.
Код не принадлежит ни одному протоколу, кроме шуточного, поэтому поведение программ с ним разное: каждая реализация HTTP решает сама, что делать с числом, которого нет в её таблице. Это и проверил стенд.
Стенд: что делают серверы
Мы заставили каждый сервер ответить кодом 418 и посмотрели на первую строку ответа — ту, что видит браузер.
| Сервер | Как задали 418 | Строка статуса |
|---|---|---|
| nginx 1.31.6 | return 418; | HTTP/1.1 418 — без текста, тело пустое |
| Apache 2.4.68, CGI | заголовок Status: 418 | HTTP/1.1 418 — без текста |
| Apache 2.4.68, mod_rewrite | RewriteRule … [R=418] | Apache не запустился |
| PHP 8.3 под Apache | http_response_code(418) | HTTP/1.1 500 Internal Server Error |
| PHP 8.3 под Apache | header("HTTP/1.1 418 I am a teapot") | HTTP/1.1 418 I am a teapot |
| встроенный сервер PHP 8.3 | http_response_code(418) | HTTP/1.1 418 Unknown Status Code |
| Node.js 20 | res.statusCode = 418 | HTTP/1.1 418 I'm a Teapot |
| Python 3.11, http.server | send_response(418) | HTTP/1.0 418 I'm a Teapot |
nginx. В исходном коде nginx (ngx_http_header_filter_module.c) на
месте 418 стоит пустая строка с пометкой «418 unused». Поэтому nginx
отправляет код без пояснения. Голый return 418; даёт пустое тело;
return 418 "текст"; или error_page 418 — тело с вашим текстом или
страницей. Не забудьте default_type: без него nginx отдал текст с типом
application/octet-stream, и браузер на стенде начал скачивать файл вместо
показа страницы.
Apache. В таблице кодов Apache (http_protocol.c) на месте 418 тоже
пусто: NULL, /* 418 */. Отсюда два следствия. mod_rewrite проверяет код
по этой таблице и на [R=418] останавливает запуск сервера с ошибкой
«RewriteRule: invalid HTTP response code '418' for flag 'R'». Тот же
флаг с кодом 410 проходит проверку.
PHP под Apache — главная ловушка. Функция ap_get_status_line для кода,
которого нет в таблице, возвращает строку кода 500. На стенде
http_response_code(418) три раза из трёх дал клиенту «500 Internal
Server Error», хотя тело страницы ушло целиком. Разработчик видит в коде
418, а браузер, мониторинг и поисковый робот получают ошибку сервера.
Если 418 действительно нужен, задавайте строку статуса полностью через
header() — тогда Apache передаёт её как есть.
Node.js и Python знают код и подписывают его «I'm a Teapot»: в Node.js — в таблице http.STATUS_CODES, в Python — как HTTPStatus.IM_A_TEAPOT.
Что видит человек в браузере
| Ответ сервера | Chromium 149 | Firefox 151 |
|---|---|---|
| 418 со своей страницей | страница сервера | страница сервера |
| 418 без тела | экран «HTTP ERROR 418», ERR_HTTP_RESPONSE_CODE_FAILURE | экран «The server … sent back an error: 418 I'm a teapot» |
| 418 без текста причины, с телом | страница сервера | страница сервера |
Если сервер прислал тело, оба браузера показывают его, и код 418 человек не увидит, пока не откроет инструменты разработчика. Если тела нет, каждый выводит свой экран. Chromium пишет: «Страница недоступна. Если проблема не исчезнет, свяжитесь с владельцем сайта. HTTP ERROR 418» — тот же экран, что для пустых 404 и 500, с ошибкой ERR_HTTP_RESPONSE_CODE_FAILURE. Firefox показывает код вместе с текстом причины и кнопку «Попробовать снова». На пустой 404 Firefox на стенде вёл себя так же.
418 в JavaScript: status и statusText
Для скриптов важно, что приходит в fetch. Мы запросили адрес с ответом 418 со страницы того же сайта.
| Протокол | status | statusText | ok |
|---|---|---|---|
| HTTP/1.1, сервер прислал «I'm a teapot» | 418 | I'm a teapot | false |
| HTTP/2, nginx | 418 | пусто | false |
Результат одинаковый в Chromium и Firefox. В HTTP/2 текста причины нет в
самом протоколе — передаётся только число. Поэтому код, который
проверяет statusText === "I'm a teapot", на HTTP/2 никогда не сработает.
Сравнивайте status, а не текст.
Как вернуть 418 у себя
Если 418 нужен вам самим — для пасхалки, теста или учебного API, — вот варианты, которые работали на стенде.
nginx. Укажите тип ответа, иначе браузер начнёт скачивать файл:
location /teapot {
default_type text/plain;
return 418 "I'm a teapot\n";
}
Node.js без фреймворков — строку статуса подставит сама платформа:
require('http').createServer((req, res) => {
res.statusCode = 418;
res.end("I'm a teapot");
}).listen(8080);
PHP под Apache — только полной строкой статуса, иначе клиент получит 500:
header("HTTP/1.1 418 I'm a teapot");
echo "I'm a teapot";
Python — модуль http.server знает код и подписывает его сам:
self.send_response(418).
Помните, что поисковый робот отнесётся к такому адресу как к несуществующей странице, и контент по нему в индекс не попадёт. Для пасхалки это нормально, для рабочего раздела сайта — нет.
Почему сайт отвечает 418
Раз код ничего не означает по стандарту, его смысл определяет тот, кто его отправил. На практике встречается несколько ситуаций.
- Пасхалка. Самый известный пример — google.com/teapot: на наш запрос 20.10.2026 Google ответил 418 по HTTP/2 со страницей «Error 418 (I'm a teapot)!?».
- Отказ роботам. Владелец сайта или его защита может отвечать 418 запросам, которые сочла автоматическими: с подозрительным User-Agent, без cookie, слишком частым. Код выбирают как шутливый намёк: «мы поняли, кто вы».
- Заглушка в API. Разработчики возвращают 418 на запрос, который API не обслуживает и не собирается, — чтобы отличить его от 404 и 400 в журналах.
- Учебные проекты и тесты. 418 удобно отправлять, чтобы проверить обработку нестандартных кодов: настоящий сервер его почти никогда не вернёт случайно.
Ни один из этих вариантов не описан в стандарте. Если вы получаете 418 от чужого сайта, ответ на вопрос «почему» знает только его владелец: код сообщает лишь о том, что сервер отказал, а причину каждый указывает в теле ответа, если вообще указывает.
Как исправить ошибку 418: посетителю
- Обновите страницу. Если код выдала защита от роботов по разовому признаку, повторный запрос, возможно, пройдёт — в таком случае ничего больше делать не нужно.
- Отключите VPN и прокси. Адреса популярных VPN часто попадают в списки подозрительных.
- Выключите расширения. Блокировщики и расширения, которые меняют заголовки, делают браузер похожим на робота.
- Разрешите cookie и JavaScript. Многие проверки ставят метку в cookie, и без неё каждый запрос выглядит первым.
- Попробуйте другой браузер или устройство. Если там сайт открывается, дело в настройках первого браузера.
- Напишите владельцу сайта. Если 418 приходит всегда, это решение сайта, а не сбой у вас.
Как исправить ошибку 418: владельцу сайта
- Найдите, кто отвечает 418. Посмотрите журнал доступа:
awk '$9==418' access.log | head. Если в вашем журнале 418 нет, код отдаёт звено перед сервером — CDN, защита от ботов, балансировщик. - Проверьте правила защиты. Если 418 отдаёт защита от ботов — своя или подключённая, — убедитесь, что правила не задевают обычных посетителей и поисковых роботов.
- Пропустите поисковых роботов. Googlebot и YandexBot проверяют по обратному DNS, а не по User-Agent. Если правило режет запросы по строке User-Agent, оно может задеть и роботов, и тех, кто их подделывает, одинаково.
- Не отвечайте 418 вместо настоящих кодов. Шутка полезна для пасхалки, но не для технических ошибок. Для запрета есть 403, для лимита — 429, для неверного метода — 405, для недоступности — 503. Их понимают браузеры, роботы и мониторинг.
- Если 418 задаёт PHP, проверьте строку статуса. Под Apache
http_response_code(418)превратится в 500. Задайте строку целиком черезheader()или выберите стандартный код.
Ошибка 418 и SEO
Google в справке о кодах ответа пишет: «All 4xx errors, except 429, are treated the same» — все ошибки 4xx, кроме 429, обрабатываются одинаково: содержимое считается несуществующим, а уже проиндексированный адрес со временем удаляется из индекса. Для поиска 418 — то же самое, что 404.
Отсюда риск. Если защита сайта отвечает 418 поисковому роботу, страницы выпадают из выдачи. Если защищаетесь от нагрузки, отвечайте 429 или 503: их Google считает временными и снижает частоту обхода, а не удаляет страницы. С PHP под Apache ещё хуже: робот получает 500, и при частых ошибках сервера Google тоже сокращает обход.
Проверить, что получает робот, можно в Search Console — инструментом проверки адреса — или в Яндекс Вебмастере, разделом «Проверка ответа сервера».
Чем 418 отличается от 403, 405 и 429
- 403 Forbidden — сервер понял запрос и отказывает в доступе. Стандартный код для запрета.
- 405 Method Not Allowed — метод запроса не разрешён для этого адреса. В HTCPCP чайник на BREW отвечал бы 418, в HTTP правильный ответ — 405.
- 429 Too Many Requests — превышен лимит запросов. Временный код, Google не выкидывает из-за него страницы.
- 418 (Unused) — значения нет, всё определяет тот, кто отправил.
Границы замера
Стенд локальный: клиент и сервер на одной машине. Проверены nginx 1.31.6 и Apache 2.4.68 из официальных образов, PHP 8.3 под Apache и встроенный сервер PHP, Node.js 20, Python 3.11, браузеры Chromium 149 и Firefox 151 через Playwright. Браузеры шли с английским интерфейсом, тексты экранов Chromium на русском взяты из его перевода. Другие версии и серверы могут вести себя иначе. Google.com/teapot мы запросили один раз, 20.10.2026.
Источники
- RFC 2324, раздел 2.3.2 «418 I'm a teapot» — rfc-editor.org
- RFC 7168, раздел 2.3.3 «418 I'm a Teapot» — rfc-editor.org
- RFC 9110, раздел 15.5.19 «418 (Unused)» — rfc-editor.org
- Реестр кодов ответа HTTP — iana.org
- Задачи nodejs/node#14644 и golang/go#21326 — github.com
- Go: net/http/status.go — github.com/golang
- nginx: ngx_http_header_filter_module.c — github.com/nginx
- Apache: http_protocol.c, mod_rewrite.c — github.com/apache
- Google: коды ответа HTTP и сканирование — developers.google.com
Похожие ошибки
- Ошибка 403 — доступ запрещён.
- Ошибка 429 — слишком много запросов.
- Ошибка 500 — внутренняя ошибка сервера; в неё превращается 418 у PHP под Apache.
- Ошибка 451 — ещё один код с литературной историей: номер взят из «451 градус по Фаренгейту».
Коротко
- 418 «I'm a teapot» — шутка из RFC 2324 от 1 апреля 1998 года.
- В RFC 9110 код назван «Unused» и зарезервирован: значения нет, но и отдать его под другую задачу пока нельзя.
- nginx и Apache отправляют 418 без текста причины, Node.js и Python — с текстом «I'm a Teapot».
- PHP под Apache на
http_response_code(418)отдаёт клиенту 500. - В HTTP/2 statusText пустой: проверяйте status, а не текст.
- Для Google 418 — как 404. Защита не должна отвечать им поисковым роботам.
