ERR_HTTP2_PROTOCOL_ERROR is a Chrome, Edge and Brave error that says a page isn't working or sent an invalid response. Under it, the connection succeeded and TLS negotiated HTTP/2, but then a frame, stream or header block violated the HTTP/2 rules (RFC 9113), so the browser aborted. You may also see it in the DevTools console for a single failed resource while the rest of the page loads. Firefox may show NS_ERROR_NET_HTTP2_SENDING_AND_RECEIVING_FRAMES or a generic network error for similar problems.
Because HTTP/2 multiplexes many requests over one connection, one bad response can break everything on that connection. The error often points at a bug or limit in the server, proxy or a device inspecting traffic, not at your code alone.
Test whether HTTP/2 is the trigger
curl -sS -o /dev/null -w "%{http_version} %{http_code}\n" --http2 https://example.com/page
curl -sS -o /dev/null -w "%{http_version} %{http_code}\n" --http1.1 https://example.com/page
If HTTP/1.1 succeeds and HTTP/2 fails, the problem is in HTTP/2 handling. Add -v to see messages such as "HTTP/2 stream 1 was not closed cleanly: PROTOCOL_ERROR" or "INTERNAL_ERROR." The HTTP/2 and HTTP/3 Checker confirms which protocols the site negotiates.
If you are a visitor
- Reload the page and then do a hard refresh. A transient proxy fault may clear.
- Clear the site's cache and cookies. Oversized or corrupted cookie headers can exceed server limits.
- Disable extensions or test in incognito. Ad blockers and request modifiers can produce malformed requests.
- Pause antivirus web or HTTPS scanning. Many security products downgrade or break HTTP/2.
- Reset Chrome's socket pools: open
chrome://net-internals/#socketsand click Flush socket pools, thenchrome://net-internals/#http2for session information. - Turn off QUIC or experimental flags if you changed them, via
chrome://flags. - Try another network or device. If the error follows the site, not you, the owner needs to fix it.
If you own the site
1. Content-Length mismatch
If a script sends a Content-Length that does not match the body (for example, PHP output modified after the header, or a compression layer changing the size), HTTP/2 treats it as a protocol error where HTTP/1.1 might limp along. Look for double compression (gzip in the app plus gzip in the proxy), output buffering bugs, and manual Content-Length headers. Fetch the URL and compare byte counts:
curl -s https://example.com/page --compressed | wc -c
curl -sI https://example.com/page | grep -i content-length
2. Headers too large
Very large cookies, many Set-Cookie headers or giant Link headers can exceed limits. In nginx, tune:
large_client_header_buffers 4 16k;
http2_max_field_size 16k; # nginx < 1.19.7; newer versions use large_client_header_buffers
Reducing header size is better than raising limits forever. Remove unnecessary cookies and avoid pushing long Link: rel=preload headers.
3. nginx or Apache HTTP/2 configuration
Confirm the module and syntax. In nginx 1.25.1 and later, enable it with the http2 on; directive; older versions use listen 443 ssl http2;. In Apache, load mod_http2 and set Protocols h2 http/1.1. For PHP under Apache, use the event or worker MPM with PHP-FPM, since mod_php requires the prefork MPM, and HTTP/2 does not work well with prefork.
As a diagnostic step, remove HTTP/2 temporarily and reload:
listen 443 ssl; # without http2 or with http2 off
If the error disappears, upgrade the server software and re-enable HTTP/2 with the current configuration style.
4. Reverse proxy and backend streaming issues
Proxies that buffer, rewrite or time out responses can send incomplete frames. Make sure proxy_http_version 1.1, adequate proxy_read_timeout, and sane buffer sizes are set when the proxy talks to the backend. Also look for errors like upstream prematurely closed connection in the log and read nginx upstream timed out.
5. Antivirus, middleboxes and WAFs
Corporate gateways and some firewalls misparse HTTP/2. If the error appears only for users behind a specific appliance, ask their administrator to update it or exclude the domain.
6. CDN edge issues
If a CDN sits in front, bypass it to test the origin (curl --resolve). When the origin works and the CDN fails, check the CDN's status and your cache or compression settings; see CDN explained.
7. Download and upload edge cases
The error can occur on file downloads when the connection is reset mid-stream, or on uploads with large bodies. Check client_max_body_size and timeouts and see nginx 413 for size limits.
Confirm the fix
- Re-run both curl commands. HTTP/2 should return the expected status.
- Verify the negotiated protocol with the HTTP/2 and HTTP/3 Checker and inspect headers with the HTTP Header Checker.
- Check TLS settings with the TLS Version Checker.
- Monitor the affected page with an uptime monitor.
Next steps
- Read HTTP/2 and HTTP/3 explained.
- Review Apache vs nginx troubleshooting.
- If the whole connection fails instead, see ERR_CONNECTION_CLOSED.
- Check protocol negotiation problems in ERR_SSL_VERSION_OR_CIPHER_MISMATCH.
FAQ
Should I just disable HTTP/2?
Only as a temporary diagnostic or workaround. It tells you where the bug is, but you lose multiplexing and header compression. Fix the underlying cause when you can.
Why does it affect only one page?
That page's response probably has a bad header, length or compression. Compare it with a working page.
Why does it work in Firefox?
Different clients enforce slightly different parts of the protocol, and Firefox may not trigger the same bug. Do not treat that as proof that the server is correct.
Is HTTP/3 affected too?
HTTP/3 uses its own error codes, but similar causes (bad headers, proxy bugs) apply. Test with curl --http3 if your build supports it.
Get notified when this fix updates
Plus occasional practical tips on uptime and monitoring, nothing else. Unsubscribe anytime.
This page is general information written by our editorial team and updated when documentation changes. Servers and providers differ, so test changes safely first. See our editorial policy and disclaimer.