{"record":{"id":"f018e6c3d733cd33","repo":"txthinking/brook","slug":"string-b","errorCode":null,"errorMessage":"string(b)","messagePattern":"string\\(b\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"websocket.go","lineNumber":156,"sourceCode":"\tif _, err := c.Write(b); err != nil {\n\t\tc.Close()\n\t\treturn nil, err\n\t}\n\tr := bufio.NewReader(c)\n\tfor {\n\t\tb, err = r.ReadBytes('\\n')\n\t\tif err != nil {\n\t\t\tc.Close()\n\t\t\treturn nil, err\n\t\t}\n\t\tb = bytes.TrimSpace(b)\n\t\tif len(b) == 0 {\n\t\t\tbreak\n\t\t}\n\t\tif bytes.HasPrefix(b, []byte(\"HTTP/1.1 \")) {\n\t\t\tif !bytes.Contains(b, []byte(\"101\")) {\n\t\t\t\tc.Close()\n\t\t\t\treturn nil, errors.New(string(b))\n\t\t\t}\n\t\t}\n\t\tif bytes.HasPrefix(b, []byte(\"Sec-WebSocket-Accept: \")) {\n\t\t\th := sha1.New()\n\t\t\th.Write([]byte(k))\n\t\t\th.Write([]byte(\"258EAFA5-E914-47DA-95CA-C5AB0DC85B11\"))\n\t\t\tak := base64.StdEncoding.EncodeToString(h.Sum(nil))\n\t\t\tif string(b[len(\"Sec-WebSocket-Accept: \"):]) != ak {\n\t\t\t\tc.Close()\n\t\t\t\treturn nil, errors.New(string(b))\n\t\t\t}\n\t\t}\n\t}\n\treturn c, nil\n}\n\ntype TLSFragmentConn struct {\n\tnet.Conn","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/txthinking/brook/blob/5cd13ef3b1fb574e88ebf2c1b5d95f2ebe1342c8/websocket.go#L138-L174","documentation":"WebSocketDial performs a WebSocket handshake and expects 'HTTP/1.1 101 Switching Protocols'. If the response starts with 'HTTP/1.1 ' but does not contain '101', the server refused the upgrade; the connection is closed and the full response is returned as the error message. The raw response is surfaced so the caller can see the server's status/reason.","triggerScenarios":"Calling WebSocketDial (directly or via CreateExchanger/TCPHandle/UDPHandle) when the WebSocket server replies with a non-101 HTTP/1.1 status - e.g. 404 on a wrong path, 401/403 auth rejected, 426 upgrade required, or 502 from an intermediary.","commonSituations":"Wrong WebSocket endpoint path or port; missing/expired auth accepted by an auth gateway in front of the socket; server not actually supporting WebSocket; a reverse proxy (nginx/CDN) blocking the Upgrade; target behind a captive portal returning an HTML error page.","solutions":["Read the error message (it contains the full HTTP response) to identify the returned status code and fix accordingly","Verify the WebSocket path, host and port are correct","Ensure any required auth handshake with the server completed before dialing","Bypass or correctly configure reverse proxies/CDNs to pass the Upgrade and Connection headers","Confirm the server actually implements the WebSocket protocol on that endpoint"],"exampleFix":"// before: dialing plain server path with a WebSocket dialer\nc, err := WebSocketDial(\"wss://host/plain-endpoint\")\n\n// after: use the endpoint that speaks WebSocket\nc, err := WebSocketDial(\"wss://host/ws\")","handlingStrategy":"try-catch","validationCode":"// Pre-check the endpoint accepts upgrades:\nresp, err := http.Get(endpoint)\nif err == nil && resp.StatusCode != http.StatusSwitchingProtocols { /* endpoint wrong */ }","typeGuard":null,"tryCatchPattern":"c, err := WebSocketDial(url)\nif err != nil {\n\tif strings.Contains(err.Error(), \"401\") || strings.Contains(err.Error(), \"403\") {\n\t\t// refresh auth, then retry\n\t} else if strings.Contains(err.Error(), \"404\") {\n\t\t// fix endpoint path\n\t}\n\treturn err\n}","preventionTips":["Verify the path/port actually serves WebSocket","Complete any required auth handshake first","Configure proxies to pass Upgrade/Connection headers"],"tags":["websocket","handshake","http"],"backgroundTag":"unexpected-http-status","analyzedSha":"5cd13ef3b1fb574e88ebf2c1b5d95f2ebe1342c8","analyzedAt":"2026-09-06T04:35:00.432Z","contentChangedAt":"2026-09-06T04:35:00.432Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}