Error during WebSocket handshake
The server did not answer the Upgrade request with a valid 101. The end of the console message says what was wrong.
What it means
A WebSocket starts as an HTTP request with the header Upgrade: websocket. The
server must answer 101 Switching Protocols with the headers Upgrade,
Connection and Sec-WebSocket-Accept
(RFC 6455 § 4.2.2).
Chrome prints this error when the answer was anything else.
DNS, the port and TLS are fine. If one of them had failed, the message would be
Error in connection establishment.
JavaScript sees only a close event with code 1006 and an
empty reason. The cause is in the console, at the end of the message.
How to fix it
Read the text after Error during WebSocket handshake:.
Unexpected response code: NNN. The status is not 101:
200: a reverse proxy dropped theUpgradeheader and the backend returned a normal page. Or the path is wrong and a single-page app returnedindex.html.400,426: usually the same dropped header, but the backend refused the request. Socket.IO also answers400when the client and server versions do not match.403: the server rejected theOriginheader or the login. Many libraries accept only the server's own origin by default.404: wrong path./wsand/ws/can be different routes.301,302: a redirect, often fromws://towss://or to a trailing slash. Browsers do not follow it. Use the final URL.502,503,504: the proxy works, the application behind it does not answer.
nginx does not pass Upgrade to the backend by default. For 200 and 400, check
these lines first:
location /ws {
proxy_pass http://app;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
Send the same request with curl to read the full answer:
curl -i -N --http1.1 --max-time 5 \
-H "Connection: Upgrade" \
-H "Upgrade: websocket" \
-H "Sec-WebSocket-Version: 13" \
-H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
https://example.com/ws
Keep --http1.1. Without it curl uses HTTP/2 where it can. HTTP/2 has no Upgrade
header, so the server answers as it would to a normal request. To reproduce a
403, add -H "Origin: https://your-site.example": a browser always sends
Origin, curl does not.
Incorrect 'Sec-WebSocket-Accept' header value, or header is missing.
The value must be the SHA-1 hash of the key plus a fixed GUID, in base64. Libraries
get it right, so this is a hand-written server. The usual mistakes: the key is
decoded from base64 before hashing, the hash is sent as hex, the GUID has a typo.
Check with the Sec-WebSocket-Accept calculator. For the
key in the curl command the correct value is s3pPLMBiTxaQ9kYGzzhZRbK+xOo=.
A message about Upgrade, Connection or Sec-WebSocket-Protocol. The status
is 101, but a header is wrong:
'Upgrade' header is missing,'Connection' header value must contain 'Upgrade': a hand-written server did not send these headers, or a proxy without WebSocket support removed them.Sent non-empty 'Sec-WebSocket-Protocol' header but no response was received: you callednew WebSocket(url, ['v1'])and the server chose no subprotocol. Browsers require it to return one of the names you offered. Choose one on the server or remove the second argument.Response must not include 'Sec-WebSocket-Protocol' header if not present in request: the server returned a subprotocol the client did not ask for.
net::ERR_…. The connection opened, but the reply was cut off or was not HTTP.
Check the port in the URL and the server log.
See it on your own traffic
Find the Upgrade request to /ws in the request list and look at the status and
the response headers. Compare Sec-WebSocket-Key in the request with
Sec-WebSocket-Accept in the response. If the request has Upgrade and
Connection and the answer is 200, a proxy dropped them or the path is wrong.
See Capture & Inspect Traffic for how Solpuga records a stream.
Tool for this page
Sec-WebSocket-Accept calculatorTurn a Sec-WebSocket-Key into the Sec-WebSocket-Accept a server must answer with, and check a pair you already have.Related
- WebSocket closed with code 1006 — how to find the causeThe connection died with no Close frame. Four causes, and how to tell them apart.
- The stream dies after 60 seconds: proxy_read_timeoutA stream that dies on the same second is a timeout, not the network. Default values in nginx, ALB, Cloudflare, Heroku and Envoy, and why a heartbeat is safer.