{"record":{"id":"d4aa2ba72d090cdd","repo":"wavetermdev/waveterm","slug":"err-error-d4aa2b","errorCode":null,"errorMessage":"err.Error()","messagePattern":"err\\.Error\\(\\)","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"pkg/web/ws.go","lineNumber":70,"sourceCode":"\tserver.SetKeepAlivesEnabled(false)\n\tlog.Printf(\"[websocket] running websocket server on %s\\n\", listener.Addr())\n\terr := server.Serve(listener)\n\tif err != nil {\n\t\tlog.Printf(\"[websocket] error trying to run websocket server: %v\\n\", err)\n\t}\n}\n\nvar WebSocketUpgrader = websocket.Upgrader{\n\tReadBufferSize:   4 * 1024,\n\tWriteBufferSize:  32 * 1024,\n\tHandshakeTimeout: 1 * time.Second,\n\tCheckOrigin:      func(r *http.Request) bool { return true },\n}\n\nfunc HandleWs(w http.ResponseWriter, r *http.Request) {\n\terr := HandleWsInternal(w, r)\n\tif err != nil {\n\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t}\n}\n\nfunc getMessageType(jmsg map[string]any) string {\n\tif str, ok := jmsg[\"type\"].(string); ok {\n\t\treturn str\n\t}\n\treturn \"\"\n}\n\nfunc getStringFromMap(jmsg map[string]any, key string) string {\n\tif str, ok := jmsg[key].(string); ok {\n\t\treturn str\n\t}\n\treturn \"\"\n}\n\nfunc processWSCommand(jmsg map[string]any, outputCh chan any, rpcInputCh chan baseds.RpcInputChType) {","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/web/ws.go#L52-L88","documentation":"HandleWs (pkg/web/ws.go:70) wraps HandleWsInternal; if the WebSocket upgrade or setup fails, the resulting error is written via http.Error with status 500. Any failure to establish the WS connection (bad handshake, internal setup error) surfaces as this plain-text 500.","triggerScenarios":"HandleWsInternal returns an error — e.g. the websocket Upgrader fails the HTTP->WS handshake because required Upgrade/Connection headers are missing or stripped, or internal initialization inside HandleWsInternal fails.","commonSituations":"Reverse proxies not forwarding the Upgrade/Connection headers (nginx without proxy_set_header Upgrade $connection_upgrade), clients connecting over plain http where only https is served, an IdempotencyToken/query param missing in the WS URL.","solutions":["Read err.Error() in the 500 response body to see the exact handshake/setup failure.","Configure the reverse proxy to pass Upgrade and Connection headers for the /ws route.","Ensure the client uses wss:// when the server is behind TLS and includes any required query parameters (e.g. idempotency token).","Confirm the route is registered (HandleWs wired into the mux) and the request method is GET."],"exampleFix":"// nginx before\nlocation /ws { proxy_pass http://backend; }\n\n// after\nlocation /ws {\n  proxy_pass http://backend;\n  proxy_http_version 1.1;\n  proxy_set_header Upgrade $http_upgrade;\n  proxy_set_header Connection \"upgrade\";\n}","handlingStrategy":"try-catch","validationCode":"// verify the endpoint is reachable and supports upgrade before opening WS\nconst probe = await fetch(wsBaseUrl.replace(\"ws\", \"http\"), {method: \"GET\"});\nif (probe.status >= 500) throw new Error(\"ws endpoint not healthy\");","typeGuard":null,"tryCatchPattern":"try {\n  const sock = new WebSocket(wsUrl);\n  sock.onerror = (e) => console.error(\"ws handshake failed\", e);\n} catch (err) {\n  console.error(\"HandleWs returned 500:\", err);\n  // fall back to polling or retry with corrected headers\n}","preventionTips":["Configure proxies to forward Upgrade/Connection headers on the ws route.","Use wss:// behind TLS and include required query params (e.g. idempotency token).","Check the 500 response body; it contains the exact handshake failure reason."],"tags":["go","websocket","handshake","internal-server-error"],"backgroundTag":"websocket-upgrade-failed","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}