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 the Upgrade header and the backend returned a normal page. Or the path is wrong and a single-page app returned index.html.
  • 400, 426: usually the same dropped header, but the backend refused the request. Socket.IO also answers 400 when the client and server versions do not match.
  • 403: the server rejected the Origin header or the login. Many libraries accept only the server's own origin by default.
  • 404: wrong path. /ws and /ws/ can be different routes.
  • 301, 302: a redirect, often from ws:// to wss:// 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 called new 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.

View in Solpuga

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