ERR_HTTP2_PROTOCOL_ERROR значит, что браузер и сервер общались по протоколу HTTP/2 и обмен прервался ошибкой протокола. Соединение установлено, сертификат принят, но ответ сервер не довёл до конца или отправил так, что браузер не может его разобрать. Мы подняли стенд с nginx и сервером, который ломается по заказу, проверили одиннадцать поломок в Chromium 149 и разбираем, какие из них дают эту ошибку и кто должен её исправлять.
Сначала полезно убедиться, что сайт вообще отвечает. Проверка доступности запрашивает страницу с нашего сервера и показывает код ответа и время отклика.
Что означает ошибка
HTTP/2 — вторая версия протокола, по которому браузер получает страницы. В отличие от HTTP/1.1, он гонит несколько запросов по одному соединению параллельно: каждый запрос — отдельный поток, данные идут кадрами, заголовки сжимаются. Версию протокола браузер и сервер выбирают в момент TLS-рукопожатия, через расширение ALPN.
Сегодня HTTP/2 является основным протоколом для открытия сайтов. 17.10.2026 мы спросили ALPN у 2056 сайтов организаций: ответили 1645, из них 1408 выбрали HTTP/2, 191 — HTTP/1.1, 46 не ответили на ALPN вовсе. Поэтому почти любой сбой на стороне сервера браузер видит именно через HTTP/2.
Ошибка относится к самому обмену. Если сервер сбрасывает поток кодом PROTOCOL_ERROR или INTERNAL_ERROR, присылает заголовок, который не помещается в пределы браузера, или посредник рвёт поток посреди ответа, Chrome пишет «Не удается получить доступ к сайту… ERR_HTTP2_PROTOCOL_ERROR».
В исходниках Chromium, в файле net_error_list.h, у неё номер -337 и описание «There is an HTTP/2 protocol error». Рядом стоят родственные коды: ERR_HTTP2_SERVER_REFUSED_STREAM (-351), ERR_HTTP2_PING_FAILED (-352), ERR_HTTP2_FLOW_CONTROL_ERROR (-361), ERR_HTTP2_FRAME_SIZE_ERROR (-362), ERR_HTTP2_COMPRESSION_ERROR (-363). Если на экране один из них, поломка того же рода, но названа точнее.
Стенд: что показывает браузер при разных поломках
Мы написали сервер HTTP/2 на Node.js, который на каждом порту ломает ответ по-своему, и подняли рядом nginx 1.22 с бэкендом, который рвёт соединение посреди тела. Открывали адреса в Chromium 149 и проверяли curl 7.88.
| Поломка на сервере | Chromium | curl |
|---|---|---|
| Поток сброшен кодом PROTOCOL_ERROR до ответа | ERR_HTTP2_PROTOCOL_ERROR | (92) stream was not closed cleanly: PROTOCOL_ERROR |
| Сброс кодом INTERNAL_ERROR, CANCEL или ENHANCE_YOUR_CALM | ERR_HTTP2_PROTOCOL_ERROR | (92) с тем же кодом |
| Сброс кодом REFUSED_STREAM | ERR_HTTP2_SERVER_REFUSED_STREAM | (56) Connection died, tried 5 times |
| Заголовок ответа на 300 000 байт | ERR_HTTP2_PROTOCOL_ERROR | (52) Empty reply from server |
| Сброс INTERNAL_ERROR после заголовков и 3000 байт тела | страница открылась обрезанной | ошибки нет, 3000 байт |
| Бэкенд за nginx оборвал тело, страница | страница открылась пустой, загрузка не закончилась | (92) stream was not closed cleanly |
| То же, запрос из скрипта (fetch) | net::ERR_HTTP2_PROTOCOL_ERROR в консоли | — |
| Соединение закрыто после 3000 байт | страница открылась | (18) stream was not closed cleanly before end |
| Объявленная длина больше тела | страница открылась | (92) PROTOCOL_ERROR |
| GOAWAY с кодом PROTOCOL_ERROR до ответа | вкладка висит без ошибки | — |
| Заголовки запроса больше общего предела nginx | ERR_CONNECTION_CLOSED | — |
Из таблицы следуют три вывода.
Ошибку дал сервер, а не браузер. Все случаи ERR_HTTP2_PROTOCOL_ERROR на стенде вызвал сервер: сброс потока или ответ, который браузер не принимает. Ничего на стороне браузера её не вызывало.
Страница и запрос из скрипта ведут себя по-разному. Если поток рвётся после того, как сервер отправил заголовки, Chromium показывает то, что успело прийти: обрезанную или пустую страницу без кода ошибки. А тот же обрыв у запроса из скрипта — fetch, загрузки картинки, стиля, ответа API — даёт в консоли «Failed to load resource: net::ERR_HTTP2_PROTOCOL_ERROR». Поэтому ошибку чаще видят разработчики в консоли, а посетитель — криво загруженный сайт.
Не всякий обрыв по HTTP/2 называется этой ошибкой. Отказ в потоке получает свой код, а слишком большие заголовки запроса nginx отбивает закрытием соединения — Chrome пишет «Сайт неожиданно разорвал соединение» и ERR_CONNECTION_CLOSED.
Cookie и большие заголовки: что на самом деле
Почти в каждой инструкции первым советом стоит очистить cookies: якобы заголовок раздувается и сервер его не принимает. Мы проверили это на nginx с настройками по умолчанию.
Предел задаёт директива large_client_header_buffers, по умолчанию
4 8k. Документация nginx говорит, что в HTTP/2 размер одного буфера
ограничивает одно поле заголовка в сжатом виде, а весь заголовок
ограничен после распаковки. Отдельные директивы http2_max_field_size и
http2_max_header_size устарели с версии 1.19.7.
Что показал стенд:
- Одна cookie на 20 000 байт от curl — nginx оборвал соединение, в журнале «client sent too large header field while processing HTTP/2 connection». По HTTP/1.1 та же cookie получила ответ 400.
- Chromium отправляет каждую cookie отдельным полем, а одна cookie в браузере не длиннее 4096 байт. Поэтому предел поля в 8 КБ браузер не превысит: 5 и 10 cookie по 4000 байт прошли.
- Общий предел сработал между 7 и 9 такими cookie: 28 КБ прошли, 36 КБ — уже нет. В журнале «client sent too large header while processing HTTP/2 connection», а в браузере — ERR_CONNECTION_CLOSED.
Вывод: очистка cookie сайта лечит раздутые заголовки, но в нашем замере такие заголовки давали другую ошибку. Попробовать её можно — это дёшево и выхода из аккаунтов на других сайтах не требует, — но надеяться на неё не стоит.
Почему возникает ошибка
На стороне сайта:
- Сброс потока самим сервером. Приложение или модуль веб-сервера падает посреди ответа, и сервер закрывает поток кодом INTERNAL_ERROR или PROTOCOL_ERROR.
- Обрыв между прокси и приложением. nginx, CDN или балансировщик получил от бэкенда половину ответа, а бэкенд закрыл соединение: упал, превысил таймаут или память. Прокси уже отправил браузеру заголовки и может только сбросить поток.
- Слишком большие заголовки ответа. Десятки Set-Cookie, огромная политика безопасности контента, служебные заголовки отладки. Заголовок на 300 000 байт на стенде давал ровно эту ошибку.
- Неверная длина ответа. Объявленный Content-Length не совпадает с телом. На стенде Chromium такую страницу открыл, но для запросов из скрипта это частая причина сбоев.
На стороне посетителя ошибка возникает, когда HTTP/2 разговаривает не сам сайт, а посредник:
- антивирус с проверкой HTTPS-трафика (Kaspersky, ESET, Dr.Web и др.) встаёт между браузером и сайтом и переписывает трафик;
- корпоративный прокси или фильтр трафика;
- VPN-клиент, который сам принимает и отдаёт соединения.
Такой посредник открывает своё соединение HTTP/2 с браузером, и если он ошибается, браузер видит ошибку протокола, хотя сайт исправен.
Пошаговая проверка: кто виноват
Действуйте от простого к сложному и после каждого шага обновляйте страницу.
- Обновите страницу клавишей F5 или Ctrl+Shift+R. Если ошибка была случайной, на этом всё.
- Откройте тот же адрес в другом браузере и на другом устройстве в другой сети. Ошибка действительно повторяется везде — проблема на стороне сайта, а не у вас.
- Ошибка только у вас — отключите по одному антивирус с проверкой HTTPS, VPN и прокси: именно они чаще всего создают конфликт.
- Запустите окно инкогнито — так видно, мешают ли расширения.
- Если сайт не открывается только при использовании рабочего компьютера, обратитесь к администратору сети: фильтр трафика настраивает он.
Сбрасывать DNS-кэш и сетевые настройки операционной системы при этой ошибке нет необходимости: раз браузер дошёл до обмена по HTTP/2, адрес сайта найден и соединение установлено.
Как исправить ошибку посетителю
Обновить страницу
Сброс потока часто случаен: бэкенд перезапустился, сработал таймаут. Если после обновления страница открылась, делать больше ничего не нужно.
Проверить с другого устройства и сети
Откройте сайт с телефона через мобильный интернет. Ошибка повторяется — она на стороне сайта, сообщите владельцу: приложите время, адрес конкретной страницы и снимок экрана с кодом. Пропала — ищите причину в своём компьютере или сети.
Отключить посредников по одному
Выключите на время проверку HTTPS в антивирусе, затем VPN, затем прокси в настройках операционной системы. Включите их обратно, когда закончите. После каждого шага обновляйте страницу. Когда ошибка пропадёт, виновник найден: обновите его или добавьте сайт в исключения.
Окно инкогнито и расширения
Запустите окно инкогнито сочетанием Ctrl+Shift+N и наберите адрес в адресной строке: в нём по умолчанию не работают расширения и нет ваших cookie. Если там сайт открылся, по одному выключайте расширения в обычном окне, особенно блокировщики рекламы и расширения, которые меняют заголовки запросов.
Удалить cookie одного сайта
Нажмите значок слева от адреса и откройте данные сайта: там можно удалить cookie только этого сайта. Чистить всю историю браузера незачем.
Обновить браузер
Если остальное не помогло, обновите браузер: в новых версиях исправляют ошибки и в работе с HTTP/2.
Что делать не нужно: отключать QUIC и править дату и время. QUIC — это HTTP/3, при нём была бы ERR_QUIC_PROTOCOL_ERROR. Неверная дата ломает проверку сертификата и даёт NET::ERR_CERT_DATE_INVALID, а не ошибку HTTP/2.
Как исправить владельцу сайта
Воспроизвести запрос
Повторите запрос curl по HTTP/2 и по HTTP/1.1:
curl -sv --http2 -o /dev/null https://example.ru/путь
curl -sv --http1.1 -o /dev/null https://example.ru/путь
По HTTP/2 сброс потока curl показывает как «HTTP/2 stream 1 was not closed cleanly: PROTOCOL_ERROR» или «INTERNAL_ERROR». Если по HTTP/1.1 ответ приходит обрезанным или с ошибкой 400 или 502, а по HTTP/2 — со сбросом, ищите причину за прокси, а не в протоколе.
Найти строку в журнале
Откройте журнал ошибок nginx на ту же минуту. Нам на стенде встречались:
- «upstream prematurely closed connection while reading upstream» — бэкенд закрыл соединение посреди ответа. Ищите падение приложения, нехватку памяти или таймаут.
- «client sent too large header field while processing HTTP/2 connection» — одно поле заголовка больше буфера.
- «client sent too large header while processing HTTP/2 connection» — все заголовки вместе больше предела.
Обе ошибки про заголовки появляются при уровне журнала info, по
умолчанию nginx пишет только error. Чтобы их увидеть, временно поставьте
error_log … info;.
Поправить конфигурацию
Дальше — способы исправить то, что нашлось в журнале.
- Заголовки запроса: увеличьте
large_client_header_buffers, например4 32k. На стенде с ним прошли заголовки, которые при 8k не проходили. Но лучше выяснить, кто ставит столько cookie. - Заголовки ответа: проверьте, что приложение не отдаёт огромные Set-Cookie и политики безопасности контента.
- Обрывы бэкенда: смотрите таймауты
proxy_read_timeout, лимиты памяти и перезапуски приложения. - Синтаксис: с nginx 1.25.1 HTTP/2 включается директивой
http2 on;, а параметрhttp2вlistenустарел.
Если перед сайтом стоит CDN, сравните ответ с CDN и напрямую с сервера-источника. Ошибка только через CDN — пишите в его поддержку.
Похожие ошибки
- ERR_QUIC_PROTOCOL_ERROR — то же, но по HTTP/3 поверх UDP.
- ERR_CONNECTION_CLOSED — соединение закрыто до ответа; на стенде её давали слишком большие заголовки запроса.
- ERR_SSL_PROTOCOL_ERROR — сбой ещё на TLS-рукопожатии, до HTTP/2.
- ERR_CONNECTION_RESET — соединение сброшено на уровне TCP.
- Ошибка 505 — сервер не принял версию HTTP из строки запроса: так nginx отвечает на «HTTP/2.0», записанный текстом.
Границы замера
- Стенд — Chromium 149 и curl 7.88 на Linux, nginx 1.22 и сервер на Node.js 20, всё на одной машине. Другие веб-серверы и CDN могут отвечать на те же поломки иначе.
- Edge, Opera, Яндекс Браузер не проверяли: у них тот же движок и тот же список ошибок, но поведение версий может отличаться.
- ALPN спрашивали 17.10.2026 из дата-центра в Германии, по одному разу.
Коротко
- ERR_HTTP2_PROTOCOL_ERROR — обмен по HTTP/2 прервался ошибкой протокола; соединение и сертификат в порядке.
- На стенде её давал сервер: сброс потока, огромный заголовок ответа, обрыв бэкенда за nginx у запросов из скрипта.
- Обрыв самой страницы Chromium показывает обрезанной без ошибки, а раздутые заголовки запроса — как ERR_CONNECTION_CLOSED.
- Посетителю: обновить, проверить с телефона, отключить антивирус с проверкой HTTPS и VPN. Отключать QUIC и править часы бесполезно.
- Владельцу: curl --http2, журнал nginx в ту же минуту, размеры заголовков и обрывы бэкенда.
