Geonode logo
Secure connection errors

How to Fix ERR_SSL_PROTOCOL_ERROR in Chrome

Tell a plain-HTTP port from a forced HTTPS upgrade or a filter, then apply the matching Chrome fix.

Updated

TL;DR

ERR_SSL_PROTOCOL_ERROR means Chrome opened a secure (TLS) handshake and the reply was not valid TLS, most often plain HTTP from a port that has no HTTPS. On a local or internal address, open it with http:// and the same port; a public site that fails everywhere needs its owner.

How Chrome and automation tools show ERR_SSL_PROTOCOL_ERROR

The error page names the host whose reply failed; Puppeteer, Playwright and ChromeDriver pass Chrome's net:: code on to your script.

WhereWhat you see
Chrome desktop, https:// address on a plain-HTTP portThis site can't provide a secure connection. localhost sent an invalid response. ERR_SSL_PROTOCOL_ERROR
Chrome desktop, http://myapp.dev:3000 typed, then upgraded to https:// by the HSTS preload listThis site can't provide a secure connection. myapp.dev sent an invalid response. ERR_SSL_PROTOCOL_ERROR
Chrome DevTools Console, a script requested over https:// from a plain-HTTP portFailed to load resource: net::ERR_SSL_PROTOCOL_ERROR
Puppeteer page.goto()net::ERR_SSL_PROTOCOL_ERROR at https://localhost:3000/
Playwright page.goto()page.goto: net::ERR_SSL_PROTOCOL_ERROR at https://localhost:3000/
Selenium with ChromeDriver, driver.get()unknown error: net::ERR_SSL_PROTOCOL_ERROR

Why this happens

Chrome expected an encrypted reply, but the server answered in plain, unencrypted text.

BoringSSL, Chrome's TLS code, expects a record whose version byte is 3, and the letters of an HTTP reply fail that test. Alerts with no Chrome code of their own, such as internal_error, land here too.

Diagnose your ERR_SSL_PROTOCOL_ERROR first

The first three need only a browser; the last two use Chrome DevTools.

  • Load the same address on another device on this Wi-Fi; if it works there, the cause sits in this computer's Chrome or proxy settings.

  • Open two unrelated https:// sites; if both fail with this code while http:// pages load, a proxy or filter is answering for every site.

  • Read the summary line; 'uses an unsupported protocol' with ERR_SSL_VERSION_OR_CIPHER_MISMATCH means the server speaks TLS but shares no version or cipher with Chrome.

  • In DevTools Network, a 307 Internal Redirect with Non-Authoritative-Reason: HSTS means Chrome rewrote http:// to https:// before connecting.

  • If the page opens with parts missing, check the DevTools Console; Failed to load resource: net::ERR_SSL_PROTOCOL_ERROR names each file that failed this way.

Solutions ranked by effectiveness

Start with the address you typed; the last fix is for whoever runs the site.

  1. Most common fix

    Open plain-HTTP ports with http://

    Applies to local or internal addresses with a port, such as :3000 or :8080, served without a certificate. Chrome uses the scheme in the address or link, whatever the port speaks.

    1. Type the whole address with http://, such as http://localhost:3000.

    2. Highlight an old https:// suggestion in the address bar and press Shift+Delete (Shift+fn+Delete on Mac).

    3. Change https:// links, redirects and asset URLs in your app that target this port.

  2. Check next

    Find what forces https:// onto your port

    Applies when http:// with a port reopens as https:// on that port. Without a port, Chrome tries 443 instead, which gives ERR_CONNECTION_REFUSED when nothing listens there.

    1. Query the host under Query HSTS domain at chrome://net-internals/#hsts.

    2. If static_upgrade_mode reads FORCE_HTTPS, serve that port over HTTPS with a certificate Chrome trusts.

    3. If only dynamic_upgrade_mode reads FORCE_HTTPS, delete that saved rule there.

  3. Site owners

    Make port 443 answer with TLS

    Applies when every network gets this code on your site, and Google's help tells visitors to contact you. Something on port 443 replies in plain text or with an alert.

    1. Trace port 443 through each hop: router, firewall, load balancer and server.

    2. Point any hop that forwards 443 to a plain-HTTP port at your TLS listener.

    3. If TLS starts but fails, read your server's TLS log for the alert it sent.

Stop the ERR_SSL_PROTOCOL_ERROR from coming back

Habits for developers and site owners that keep http:// services and HTTPS rules from colliding.

  1. Pick .test for dev host names; RFC 6761 reserves it for testing, and Chrome preloads no .test rule.

  2. Raise HSTS max-age in stages, starting at 300 seconds, so a forgotten HTTP subdomain breaks only briefly.

  3. Move internal subdomains to HTTPS before adding includeSubDomains or preload; leaving the preload list takes months.

Exact-city checks of your siteGeonode's default strict matching returns HTTP 465 rather than switch to another city.
Try residential proxies

Related errors

Learn more

FAQ

It is Chromium's net error -107: Chrome began a TLS handshake and the reply broke the protocol, usually plain HTTP on an https:// port. The fix depends on who sent that reply.

The server behind that port speaks plain HTTP while the address asked for https://. Chrome ignores HSTS for localhost, even rules saved earlier, so the scheme came from the address or a link; use http:// instead.

Chrome's HSTS preload list holds whole endings such as .dev, .app, .page, .new, .day and .foo, subdomains included, so every name under them opens over https://. A dev server without TLS on such a name fails this way.

Yes, if it answers inside the HTTPS tunnel with a plain page, as our test proxy did. A plain HTTP proxy entered with https:// gave ERR_PROXY_CONNECTION_FAILED instead, and a clean CONNECT tunnel passes the site's own reply.

No. The page offers only Reload, and a switch that skips certificate checks changed nothing in our test, because the reply failed before any certificate arrived. Such switches also hide real problems and expose your traffic.

Chrome hit this error while loading the page: Puppeteer's page.goto() throws it with the URL, and ChromeDriver returns unknown error: net::ERR_SSL_PROTOCOL_ERROR. Check whether your test's base URL uses https:// for a plain-HTTP dev server.

A proxy that covers Incognito

Set Geonode as your system proxy, and Chrome's Incognito windows use it as well.