ERR_HTTP2_PROTOCOL_ERROR とは?原因と解決方法
ポイント
ERR_HTTP2_PROTOCOL_ERROR(Chromium のエラー -337)は、ページを運ぶ HTTP/2 ストリームが失敗したことを示します。サーバー、プロキシ、CDN が途中でストリームをリセットしたか(Chrome はこの種のリセットをすべて -337 として報告します)、HTTP/2 のルールに反するヘッダーを Chrome が拒否したかのどちらかです。訪問者側では、再読み込み、シークレットウィンドウ、そのサイトの Cookie の削除、ウイルス対策ソフトの HTTPS スキャンの一時停止で通ることもありますが、多くはサイト側でしか直せません。サイト運営者側の主な原因は、サーバーやプロキシが最後まで返せなかった応答(ディスクの空き容量不足、書き込めない一時フォルダ、アプリのクラッシュ)、本文と一致しない Content-Length、Transfer-Encoding のような禁止ヘッダーです。curl --http2 -v で再現できます。
今すぐ確認

読み始める
- ERR_
HTTP2_ PROTOCOL_ ERROR とは? - HTTP/2 が不正な形式とみなすもの
- ERR_
HTTP2_ PROTOCOL_ ERROR の原因 - 解決策1:スーパーリロードとシークレットモードを試す
- 解決策2:そのサイトの Cookie とキャッシュを削除する
- 解決策3:ウイルス対策ソフトの HTTPS スキャンと拡張機能を一時停止する
- 解決策4:Chrome を更新し、他のブラウザでも確認する
- 解決策5:HTTP/2 なしでページをテストする
- サイト管理者向け:HTTP/2 プロトコルエラーを直す
- 1. curl で再現する
- 2. ストリームの途中で途切れた応答を確認する
- 3. Content-Length と禁止ヘッダーを修正する
- ERR_
HTTP2_ PROTOCOL_ ERROR と似たエラーの違い - よくある質問
ERR_HTTP2_PROTOCOL_ERROR とは?
ERR_HTTP2_PROTOCOL_ERROR は、ページを運ぶ HTTP/2 ストリームが失敗したことを示す Chrome と Edge のエラーです。サーバーが完了前にストリームをリセットしたか、ブラウザが拒否するヘッダーを送ったことを意味します。Chromium 内部ではネットエラー -337 にあたり、「There is an HTTP/2 protocol error」と説明されています(net_error_list.h)。Chrome にはこのエラー専用のエラーページがないため、汎用のページが表示されます。「このサイトにアクセスできません。… のウェブページは一時的に停止しているか、新しいウェブアドレスに移動した可能性があります。」というメッセージの下に、ERR_HTTP2_PROTOCOL_ERROR と表示されます。Edge も独自のエラー画面に同じコードを表示します。
HTTP/2 は、現在ほとんどの HTTPS サイトが使っている高速版の HTTP です。各リクエストは 1 本の接続の中で独立したストリームとして流れ、どちらの側もリセットでストリームを取り消せます。Chrome はサーバーからのリセットを、サーバー側の理由にかかわらずプロトコルエラーとして報告します。また、ヘッダーが HTTP/2 のルールに反している場合(Transfer-Encoding ヘッダー、ヘッダー名の大文字、ステータスの欠落など)は、Chrome 自身がストリームを取り消します。
開発者は DevTools のコンソールで net::ERR_HTTP2_PROTOCOL_ERROR 200 (OK) という形でよく目にします。この組み合わせは強い手がかりです。ヘッダーは正しく、サーバーは 200 を返しましたが、本文が届いている途中でストリームが失敗したことを示しています。
ページが実際に送っているヘッダーを確認する
HTTP/2 が不正な形式とみなすもの
HTTP/2 の標準規格(RFC 9113)は、応答を不正な形式にする誤りを列挙しています。実際のエラーの大半はこれらの問題が原因で、それぞれがブラウザに届く仕組みは次のとおりです。
| ルール | 違反する例 |
|---|---|
| Content-Length は本文のサイズと一致していなければならない | サーバーやプラグインが宣言したサイズと実際に送ったサイズが違う。手前のプロキシ、CDN、サーバーがストリームをリセットする |
| 応答はきれいに終わらなければならない | サーバー、プロキシ、アプリが応答を完了できず(ディスクの空き容量不足、クラッシュ、タイムアウト)、ストリームをリセットする。nginx は、開始済みの応答を完了できないときにこれを行う |
| 接続固有のヘッダーは禁止 | HTTP/2 の応答に含まれる Transfer-Encoding(Chrome は拒否)。Connection、Keep-Alive、Proxy-Connection、Upgrade も禁止で、curl のような厳格なクライアントは拒否する |
| フィールド名は小文字でなければならない | 大文字を含むヘッダー名が、そのまま HTTP/2 に渡される |
| 有効なヘッダー値 | ヘッダー値の中の改行やその他の禁止文字 |
| 有効な :status 擬似ヘッダー | ステータスコードの欠落や判読不能 |
ERR_HTTP2_PROTOCOL_ERROR の原因
ほとんどのケースはサーバー側が原因ですが、あなた自身のコンピューター上にも、届く途中の応答を壊してしまうものがいくつかあります。
- サーバー側: サーバーやプロキシが最後まで返せない応答(ディスク容量が尽きた、または一時ファイルを書き込めないプロキシ、ストリーミング中にクラッシュするアプリ、タイムアウト)、手前のプロキシが諦める原因になる誤った Content-Length の値、禁止された、または無効なヘッダー、古いサーバーや CDN 設定での HTTP/2 サポートの不具合。
- 利用者側: HTTPS を検査して通信を書き換えるウイルス対策ソフトやファイアウォール、リクエストやレスポンスを変更するブラウザ拡張機能、サーバーが正しく処理できないリクエスト(たとえば大きすぎる Cookie)、そしてまれに古い Chrome のバージョン。
解決策1:スーパーリロードとシークレットモードを試す
Ctrl + Shift + R(Mac は Cmd + Shift + R)を押して、キャッシュを使わずに再読み込みします。一度途切れた応答でも、次の試行では問題なく届くことがあります。
次に、シークレット ウィンドウでページを開きます(Ctrl + Shift + N、Mac は Cmd + Shift + N)。シークレットモードには Cookie も通常のプロファイルのキャッシュもなく、拡張機能もデフォルトでオフになっています。そこでページが表示されるなら、通常のウィンドウでは解決策2または解決策3で直せます。
解決策2:そのサイトの Cookie とキャッシュを削除する
サイトの Cookie とキャッシュを削除すると、Chrome が送るリクエストが変わり(Cookie が減り、再検証するキャッシュもなくなり)、サーバー側の不具合を回避できることがあります。アドレスバーの左にある サイト情報を表示 をクリック → Cookie とサイトデータ → デバイス上のサイトデータを管理 → 削除して再読み込みします。より広く削除したい場合は、Ctrl + Shift + Delete を押して、過去 7 日間 の キャッシュされた画像とファイル を削除してください。
解決策3:ウイルス対策ソフトの HTTPS スキャンと拡張機能を一時停止する
HTTPS を復号して検査するセキュリティソフトは、すべての HTTP/2 接続の中間に位置しています。その HTTP/2 の処理に不具合があったり古かったりすると、ストリームを壊したり、Chrome が拒否するヘッダーをそのまま渡してしまったりすることがあります。HTTPS スキャン機能だけをオフにして(Avast/AVG:Web シールド → Enable HTTPS scanning、ESET:SSL/TLS プロトコルフィルタリング、Kaspersky:暗号化された接続をスキャンする)、再読み込みしてください。これで直るなら、ウイルス対策ソフトを更新し、そのサイトを除外リストに追加します。
次に、chrome://extensions ですべての拡張機能を無効にして再読み込みし、1 つずつ有効に戻していきます。広告ブロッカー、プライバシー系ツール、ヘッダーを編集するものが典型的な原因です。
解決策4:Chrome を更新し、他のブラウザでも確認する
chrome://settings/help を開いて保留中の更新をインストールし、ブラウザを再起動します。その後、同じページを Firefox や Safari で、さらに別の端末やネットワークでも開いてみてください。どこでも失敗するなら、サイト自体が壊れており、直せるのは運営者だけです(ウイルス対策ソフトの HTTPS スキャンは 1 台のパソコン上のすべてのブラウザに影響するため、2 台目の端末が本当のテストになります)。Chrome や Edge だけが失敗する場合、サイトが Chrome の拒否するヘッダーを送っている可能性が高いですが、解決策2と3をもう一度試す価値はあります。
解決策5:HTTP/2 なしでページをテストする
Chrome は HTTP/2(と HTTP/3)をオフにして起動でき、HTTP/2 が関係しているかどうかを確認できます。ターミナルから 2 つ目の別の Chrome を起動します。追加のプロファイルフォルダを指定すると、通常の Chrome が開いたままでも新しいインスタンスになります。
# Windows (Command Prompt)
"C:\Program Files\Google\Chrome\Application\chrome.exe" --user-data-dir="%TEMP%\h2test" --disable-http2 --disable-quic
# macOS (Terminal)
open -na "Google Chrome" --args --user-data-dir=/tmp/h2test --disable-http2 --disable-quicそのウィンドウでページが読み込まれるなら、HTTP/2 の応答が問題であり、運営者が修正する必要があります。ERR_CONTENT_LENGTH_MISMATCH や ERR_INCOMPLETE_CHUNKED_ENCODING で失敗するようになった場合は、プロトコルにかかわらずサーバーが応答を途中で切っています。終わったらそのウィンドウを閉じてください。通常の Chrome には影響しません。
サイト管理者向け:HTTP/2 プロトコルエラーを直す
異なるネットワークやブラウザの訪問者からこのエラーが報告されている場合、問題はあなたのサーバー環境にあります。次の3つの確認で、ほぼすべての原因を見つけられます。
1. curl で再現する
# HTTP/2: watch the end of the output
curl -sv --http2 https://example.com/broken-page -o /dev/null
# A stream the server gave up on ends with something like:
# HTTP/2 stream 1 was not closed cleanly: INTERNAL_ERROR (err 2)
# (curl 8.19+: HTTP/2 stream 1 reset by server (error 0x2 INTERNAL_ERROR);
# "reset by curl" means curl rejected the response itself)
# Same URL over HTTP/1.1 for comparison
curl -sv --http1.1 https://example.com/broken-page -o /dev/nullHTTP/1.1 では動いて HTTP/2 では失敗するなら、HTTP/2 が関係しています。「Reset by server」は、サーバーまたはプロキシが応答の途中で諦めたことを示します。curl は Chrome とまったく同じ項目を検査するわけではない(Chrome が通す Content-Length の不一致や接続ヘッダーを curl は拒否します)ため、証拠ではなく強い手がかりとして扱ってください。HTTP ヘッダーチェッカーでは、アプリが設定しているヘッダーをネットワークの外側から確認できます。
2. ストリームの途中で途切れた応答を確認する
サーバー側で最も多い原因は、始まったのに(ステータス 200、ヘッダー送信済み)最後まで完了できない応答です。nginx はアプリからの大きめの応答を一時ファイルにバッファリングするため、ディスクがいっぱいだったり、nginx が一時フォルダに書き込めなかったりすると、ストリームをリセットし、ブラウザはプロトコルエラーを報告します。次を確認してください。
df -h # is any disk full?
sudo grep -E "No space left|Permission denied" /var/log/nginx/error.log | tail
ls -ld /var/lib/nginx/proxy /var/lib/nginx/fastcgi # Debian/Ubuntu packages
ls -ld /var/cache/nginx/proxy_temp /var/cache/nginx/fastcgi_temp # nginx.org packages
# the temp folders must be writable by the nginx worker userアプリ自体も確認しましょう。大きなページやダウンロードをストリーミング中に PHP や Node のプロセスがクラッシュしたり、タイムアウトしたり、メモリ上限に達したりしても、同じ結果になります。エラーが発生した時刻前後のアプリのログに、たいてい原因が記録されています。
3. Content-Length と禁止ヘッダーを修正する
- Content-Length: サーバーに計算させましょう。プラグイン、ミドルウェア、Web サーバーも出力を圧縮・変更する場合は、アプリのコードで手動設定しないでください。宣言した長さが実際に送ったバイト数と一致しなくなるためです。PHP のコードで長さを設定しつつ、プラグインや PHP の設定も出力を圧縮している状態は、WordPress サイトでこれが起きる原因の一つです。
- Transfer-Encoding: HTTP/2 の応答では絶対に送らないでください。Chrome は見つけた時点でストリームをリセットします。RFC 9113 は
Connection、Keep-Alive、Proxy-Connection、Upgradeも禁止しています。Chrome はこれらを無視しますが、curl などの厳格なクライアントは拒否し、nginx はプロキシ経由の応答からほとんどを自動的に取り除きます。 - ヘッダー値: どのヘッダーにも改行や制御文字が含まれていないことを確認してください。
Content-Dispositionのファイル名のように、ユーザー入力がそのままヘッダーに入ることが原因になりがちです。 - 手前の CDN: Cloudflare などの CDN を使っている場合は、オリジンを直接テストして(curl の
--resolveや hosts エントリを使用)、エラーの出どころがオリジンか CDN かを切り分けます。
ERR_HTTP2_PROTOCOL_ERROR と似たエラーの違い
| エラー | コード | 何が起きたか |
|---|---|---|
| ERR_HTTP2_PROTOCOL_ERROR | -337 | HTTP/2 の応答がプロトコルのルールに違反した |
| ERR_QUIC_PROTOCOL_ERROR | -356 | HTTP/3(QUIC)で起きる同種の失敗 |
| ERR_SSL_PROTOCOL_ERROR | -107 | HTTP/2 が始まる前に HTTPS(TLS)のハンドシェイクが失敗した |
| ERR_CONNECTION_CLOSED | -100 | ページが届く前に接続が閉じられた |
| ERR_EMPTY_RESPONSE | -324 | サーバーが何も送ってこなかった |
詳しいガイド:ERR_QUIC_PROTOCOL_ERROR、ERR_SSL_PROTOCOL_ERROR、ERR_CONNECTION_CLOSED、ERR_EMPTY_RESPONSE。サイトの証明書と HTTPS の設定を外部から確認するには、SSL 証明書チェック を使ってください。
サイトが実際に送っているヘッダーを確認する
DNS Robot の HTTP ヘッダーチェッカーは、当社のサーバーから HTTP/1.1 で任意の URL を取得し、ステータスコードとアプリが設定しているすべてのレスポンスヘッダー(Content-Length、Content-Encoding、Content-Disposition)を一覧表示します。curl --http2 の出力と比較できます。
出典
- net_error_list.h(HTTP2_PROTOCOL_ERROR -337), Chromium
- RFC 9113:HTTP/2、不正な形式のメッセージ, IETF
- HTTP/2:ERR_HTTP2_PROTOCOL_ERROR, Cloudflare


