ERR_HTTP2_PROTOCOL_ERROR: Meaning & Fix in Chrome and Edge

Key takeaway

ERR_HTTP2_PROTOCOL_ERROR (Chromium error -337) means the HTTP/2 stream carrying the page failed. Either the server, proxy or CDN reset it partway (Chrome reports any such reset as -337), or Chrome rejected headers that break HTTP/2's rules. For visitors, a reload, an Incognito window, clearing the site's cookies or pausing antivirus HTTPS scanning sometimes gets past it, but usually only the site can fix it. For site owners the usual causes are a response the server or proxy couldn't finish (a full disk, an unwritable temp folder, a crashing app), a Content-Length that doesn't match the body, or a forbidden header such as Transfer-Encoding. Reproduce it with curl --http2 -v.

Check it now

Chrome error page with ERR_HTTP2_PROTOCOL_ERROR beside the checks that fix HTTP/2 protocol errors
Chrome error page with ERR_HTTP2_PROTOCOL_ERROR beside the checks that fix HTTP/2 protocol errors
Start reading
  1. What Is ERR_HTTP2_PROTOCOL_ERROR?
  2. What HTTP/2 Treats as Malformed
  3. What Causes ERR_HTTP2_PROTOCOL_ERROR?
  4. Fix 1: Hard Reload and Try Incognito
  5. Fix 2: Clear That Site's Cookies and Cached Files
  6. Fix 3: Pause Antivirus HTTPS Scanning and Extensions
  7. Fix 4: Update Chrome and Check Other Browsers
  8. Fix 5: Test the Page Without HTTP/2
  9. For Website Owners: Fixing HTTP/2 Protocol Errors
  10. 1. Reproduce It With curl
  11. 2. Check for Responses Cut Off Mid-Stream
  12. 3. Fix Content-Length and Forbidden Headers
  13. ERR_HTTP2_PROTOCOL_ERROR vs Similar Errors
  14. Frequently Asked Questions

What Is ERR_HTTP2_PROTOCOL_ERROR?

ERR_HTTP2_PROTOCOL_ERROR is a Chrome and Edge error meaning the HTTP/2 stream carrying the page failed: the server reset it before it finished, or sent headers the browser rejects. In Chromium it is net error -337: "There is an HTTP/2 protocol error" (net_error_list.h). Chrome has no dedicated error page for it, so you see the generic one: "This site can't be reached. The webpage at … might be temporarily down or it may have moved permanently to a new web address," with ERR_HTTP2_PROTOCOL_ERROR underneath. Edge shows the same code on its own "Hmm… can't reach this page" screen.

HTTP/2 is the faster version of HTTP that most HTTPS sites now use. Each request travels as its own stream inside one connection, and either side can cancel a stream with a reset. Chrome reports any reset from the server as a protocol error, whatever the server's reason, and it also cancels a stream itself when the headers break HTTP/2's rules (a Transfer-Encoding header, capital letters in a header name, a missing status).

Developers often see it in the DevTools console as net::ERR_HTTP2_PROTOCOL_ERROR 200 (OK). That combination is a strong clue: the headers were valid and the server answered 200, but the stream failed while the body was arriving.

See the headers a page really sends

What HTTP/2 Treats as Malformed

The HTTP/2 standard (RFC 9113) lists the mistakes that make a response malformed. These are the problems behind most real-world errors, and how each one reaches the browser:

RuleWhat breaks it
Content-Length must equal the body sizeA server or plugin declares one size and sends another; the proxy, CDN or server in front then resets the stream
The response must end cleanlyThe server, proxy or app can't finish (a full disk, a crash, a timeout) and resets the stream; nginx does this when it can't complete a response it has started
No connection-specific headersTransfer-Encoding in an HTTP/2 response (Chrome rejects it); Connection, Keep-Alive, Proxy-Connection and Upgrade are forbidden too, and strict clients such as curl reject them
Field names must be lowercaseHeader names with capital letters passed straight through to HTTP/2
Valid header valuesNewlines or other forbidden characters inside a header value
A valid :status pseudo-headerA missing or unreadable status code

What Causes ERR_HTTP2_PROTOCOL_ERROR?

Most cases come from the server side, but a few things on your own computer can damage a response on its way in:

  • On the server: a response the server or proxy can't finish (a proxy that runs out of disk space or can't write its temp files, an app that crashes while streaming, a timeout), wrong Content-Length values that make the proxy in front give up, forbidden or invalid headers, and buggy HTTP/2 support in an older server or CDN configuration.
  • On your side: antivirus or firewall software that inspects HTTPS and rewrites traffic, browser extensions that modify requests or responses, a request the server mishandles (for example oversized cookies), and occasionally an outdated Chrome build.

Fix 1: Hard Reload and Try Incognito

Press Ctrl + Shift + R (Mac: Cmd + Shift + R) to reload without the cache. A response that was cut off once may come through fine on the next try.

Then open the page in an Incognito window (Ctrl + Shift + N, Mac Cmd + Shift + N). Incognito has no cookies, no cache from your normal profile, and extensions are off by default. If the page loads there, Fix 2 or Fix 3 will solve it in your normal window.

Fix 2: Clear That Site's Cookies and Cached Files

Clearing the site's cookies and cached files changes the request Chrome sends (fewer cookies, no cached copy to revalidate), which can avoid a server bug. Click View site information at the left of the address bar → Cookies and site data → Manage on-device site data → delete, then reload. For a broader clean, press Ctrl + Shift + Delete and clear Cached images and files for the Last 7 days.

Fix 3: Pause Antivirus HTTPS Scanning and Extensions

Security software that decrypts and inspects HTTPS sits in the middle of every HTTP/2 connection. If its HTTP/2 handling is buggy or out of date, it can break streams or pass on headers Chrome rejects. Turn off only the HTTPS-scanning feature (Avast/AVG: Web Shield → Enable HTTPS scanning; ESET: SSL/TLS protocol filtering; Kaspersky: Scan encrypted connections) and reload. If that fixes it, update the antivirus and add an exclusion for the site.

Next, disable all extensions at chrome://extensions, reload, then turn them back on one at a time. Ad blockers, privacy tools and anything that edits headers are the usual suspects.

Fix 4: Update Chrome and Check Other Browsers

Open chrome://settings/help to install any pending update, then restart the browser. Then open the same page in Firefox or Safari, and on another device or network. If it fails everywhere, the site is broken and only its owner can fix it (antivirus HTTPS scanning affects every browser on one computer, so a second device is the real test). If only Chrome or Edge fails, the site is probably sending a header Chrome rejects; Fixes 2 and 3 are still worth repeating.

Fix 5: Test the Page Without HTTP/2

Chrome can be started with HTTP/2 (and HTTP/3) switched off, which shows whether HTTP/2 is involved. Start a second, separate Chrome from a terminal; the extra profile folder makes it a new instance even while your normal Chrome is open:

bash
# 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

If the page loads in that window, its HTTP/2 responses are the problem and the owner needs to fix them. If it now fails with ERR_CONTENT_LENGTH_MISMATCH or ERR_INCOMPLETE_CHUNKED_ENCODING, the server is cutting the response short whatever the protocol. Close that window when you're done; your normal Chrome is unaffected.

For Website Owners: Fixing HTTP/2 Protocol Errors

If visitors on different networks and browsers report the error, the problem is in your stack. These three checks find almost all of them.

1. Reproduce It With curl

bash
# 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/null

If HTTP/1.1 works and HTTP/2 fails, HTTP/2 is involved. "Reset by server" points to the server or a proxy giving up mid-response. curl doesn't check exactly what Chrome checks (it rejects Content-Length mismatches and connection headers Chrome lets through), so treat it as a strong hint, not proof. The HTTP Header Checker lists the headers your app sets, seen from outside your network.

2. Check for Responses Cut Off Mid-Stream

The most common server-side cause is a response that starts (status 200, headers sent) and then can't be finished. nginx buffers larger responses from your app into temporary files, and if the disk is full or nginx can't write to its temp folder, it resets the stream and the browser reports a protocol error. Check:

bash
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

Also check the app itself: a PHP or Node process that crashes, times out or hits a memory limit while streaming a large page or download produces the same result. App logs around the time of the error usually show it.

3. Fix Content-Length and Forbidden Headers

  • Content-Length: let the server calculate it. Don't set it by hand in app code if a plugin, middleware or the web server also compresses or modifies the output, because the declared length then no longer matches the bytes sent. A length set in PHP code while a plugin or PHP setting also compresses the output is one way this happens on WordPress sites.
  • Transfer-Encoding: never send it in an HTTP/2 response; Chrome resets the stream when it sees one. RFC 9113 also forbids Connection, Keep-Alive, Proxy-Connection and Upgrade. Chrome ignores those, but curl and other strict clients reject them, and nginx strips most of them from proxied responses for you.
  • Header values: make sure no header contains a line break or a control character. This often comes from user input placed in a header, such as a filename in Content-Disposition.
  • CDN in front: if you use Cloudflare or another CDN, test the origin directly (with curl --resolve or a hosts entry) to tell whether the error comes from the origin or from the CDN.

ERR_HTTP2_PROTOCOL_ERROR vs Similar Errors

ErrorCodeWhat happened
ERR_HTTP2_PROTOCOL_ERROR-337An HTTP/2 response broke the protocol rules
ERR_QUIC_PROTOCOL_ERROR-356The same kind of failure over HTTP/3 (QUIC)
ERR_SSL_PROTOCOL_ERROR-107The HTTPS (TLS) handshake failed before HTTP/2 started
ERR_CONNECTION_CLOSED-100The connection was closed before a page arrived
ERR_EMPTY_RESPONSE-324The server sent nothing at all

Detailed guides: ERR_QUIC_PROTOCOL_ERROR, ERR_SSL_PROTOCOL_ERROR, ERR_CONNECTION_CLOSED and ERR_EMPTY_RESPONSE. To check a site's certificate and HTTPS setup from outside, use the SSL Checker.

See the headers your site really sends

DNS Robot's HTTP Header Checker fetches any URL over HTTP/1.1 from our servers and lists the status code and every response header your app sets (Content-Length, Content-Encoding, Content-Disposition), so you can compare them with what curl --http2 shows.

Sources

  1. net_error_list.h (HTTP2_PROTOCOL_ERROR -337), Chromium
  2. RFC 9113: HTTP/2, malformed messages, IETF
  3. HTTP/2: ERR_HTTP2_PROTOCOL_ERROR, Cloudflare

Frequently Asked Questions

What does ERR_HTTP2_PROTOCOL_ERROR mean?

It means the HTTP/2 stream carrying the page failed. Usually the server, a proxy or the CDN reset it before the response finished, which Chrome reports as a protocol error; sometimes Chrome rejected headers HTTP/2 forbids, such as Transfer-Encoding. In Chromium it is net error -337.

Is ERR_HTTP2_PROTOCOL_ERROR my fault or the website's?

Usually the website's. Antivirus HTTPS scanning, browser extensions or oversized cookies can also trigger it, so try a hard reload, an Incognito window and pausing HTTPS scanning first. If it fails in every browser and on every network, only the site owner can fix it.

What does net::ERR_HTTP2_PROTOCOL_ERROR 200 mean?

The headers were valid and the server answered 200, but the stream failed while the body was arriving: the server, proxy or CDN reset it partway. The usual causes are a proxy that ran out of disk space or couldn't write temp files, an app that crashed mid-response, or a Content-Length that doesn't match the body.

How do I fix ERR_HTTP2_PROTOCOL_ERROR in Chrome?

Hard-reload with Ctrl + Shift + R, try Incognito, clear the site's cookies and cached files, pause antivirus HTTPS scanning, disable extensions and update Chrome. To test whether HTTP/2 is involved, start a separate Chrome with --user-data-dir, --disable-http2 and --disable-quic and see whether the page loads.

Can I disable HTTP/2 in Chrome?

Not from the settings page. For testing, start a separate Chrome with --disable-http2 and --disable-quic (plus --user-data-dir, or a running Chrome ignores the flags). It applies only to that launch. It's a diagnostic, not a long-term fix, because HTTP/2 makes sites faster.

Why does ERR_HTTP2_PROTOCOL_ERROR happen on my nginx site?

Check whether the disk is full or nginx can't write to its proxy or FastCGI temp folders (look for "No space left on device" or "Permission denied" in the error log), whether the app crashes mid-response, and whether your app sends a Transfer-Encoding header or a wrong Content-Length. Reproduce it with curl --http2 -v.

Can Cloudflare cause ERR_HTTP2_PROTOCOL_ERROR?

Usually the origin is at fault. Cloudflare's docs list malformed origin headers and compression problems (a gzip body whose Content-Length wasn't updated, or broken gzip) as the usual causes, and they may only show when traffic goes through Cloudflare. Test the origin directly, bypassing Cloudflare.

What is the difference between ERR_HTTP2_PROTOCOL_ERROR and ERR_QUIC_PROTOCOL_ERROR?

They are the same kind of failure in different protocols. ERR_HTTP2_PROTOCOL_ERROR happens over HTTP/2 (on TCP), ERR_QUIC_PROTOCOL_ERROR over HTTP/3 (on QUIC). Firewalls and antivirus software that interfere with QUIC are a common extra cause of the second one.

Does clearing the cache fix ERR_HTTP2_PROTOCOL_ERROR?

Sometimes. Clearing the site's cookies and cached files changes the request Chrome sends, which can avoid a server bug, so it's worth trying. If the server keeps resetting the stream or sending bad headers, the error comes back until the site is fixed.

About the author

Shaik Vahid

Founder of DNS Robot. Vahid spent years in web hosting support fixing domains, DNS records, SSL certificates and email delivery for customers. He builds DNS Robot's tools and writes these guides from the errors people actually hit.

HTTP Header Checker

Response headers exactly as sent, with a Mozilla Observatory security grade