nats-io/nats-server · error
invalid websocket connection
Error message
invalid websocket connection
What it means
Set during the leaf-node WebSocket client handshake when the HTTP response is not a valid 101 Switching Protocols upgrade: wrong status code, missing Upgrade/Connection headers, or a Sec-Websocket-Accept key that does not match wsAcceptKey(wsKey). It means the remote endpoint did not complete the WebSocket handshake correctly.
Source
Thrown at server/leafnode.go:3677
if noMasking {
req.Header.Add(wsNoMaskingHeader, wsNoMaskingValue)
}
c.nc.SetDeadline(time.Now().Add(infoTimeout))
if err := req.Write(c.nc); err != nil {
return nil, WriteError, err
}
var resp *http.Response
br := bufio.NewReaderSize(c.nc, MAX_CONTROL_LINE_SIZE)
resp, err = http.ReadResponse(br, req)
if err == nil &&
(resp.StatusCode != 101 ||
!strings.EqualFold(resp.Header.Get("Upgrade"), "websocket") ||
!strings.EqualFold(resp.Header.Get("Connection"), "upgrade") ||
resp.Header.Get("Sec-Websocket-Accept") != wsAcceptKey(wsKey)) {
err = fmt.Errorf("invalid websocket connection")
}
// Check compression extension...
if err == nil && c.ws.compress {
// Check that not only permessage-deflate extension is present, but that
// we also have server and client no context take over.
srvCompress, noCtxTakeover := wsPMCExtensionSupport(resp.Header, false)
// If server does not support compression, then simply disable it in our side.
if !srvCompress {
c.ws.compress = false
} else if !noCtxTakeover {
err = fmt.Errorf("compression negotiation error")
}
}
// Same for no masking...
if err == nil && noMasking {
// Check if server accepts no masking
if resp.Header.Get(wsNoMaskingHeader) != wsNoMaskingValue {View on GitHub (pinned to 3a66a489d2)
Solutions
- Confirm the leaf node URL actually points to a WebSocket-enabled leaf node port
- Check for intermediaries (proxies, load balancers) that strip Upgrade headers
- Verify the server supports WebSockets on that port and shares the same accept-key logic
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at server/leafnode.go:3677 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/786297b9cf0850ea.
Report an issue: GitHub.