{"record":{"id":"11fe0c408ef5a52a","repo":"browsh-org/browsh","slug":"error-starting-websocket-server-w","errorCode":null,"errorMessage":"Error starting websocket server: %w","messagePattern":"Error starting websocket server: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"interfacer/src/browsh/comms.go","lineNumber":36,"sourceCode":"\t\tReadBufferSize:  1024,\n\t\tWriteBufferSize: 1024,\n\t}\n\tstdinChannel              = make(chan string)\n\tIsConnectedToWebExtension = false\n)\n\ntype incomingRawText struct {\n\tRequestID string `json:\"request_id\"`\n\tRawJSON   string `json:\"json\"`\n}\n\nfunc startWebSocketServer() {\n\tserverMux := http.NewServeMux()\n\tserverMux.HandleFunc(\"/\", webSocketServer)\n\tport := viper.GetString(\"browsh.websocket-port\")\n\tslog.Info(\"Starting websocket server...\")\n\tif netErr := http.ListenAndServe(\":\"+port, serverMux); netErr != nil {\n\t\tShutdown(fmt.Errorf(\"Error starting websocket server: %w\", netErr))\n\t}\n}\n\nfunc sendMessageToWebExtension(message string) {\n\tif !IsConnectedToWebExtension {\n\t\tslog.Info(\"Webextension not connected. Message not sent\", \"message\", message)\n\t\treturn\n\t}\n\tstdinChannel <- message\n}\n\n// Listen to all messages coming from the webextension\n// TODO: It seems this *also* receives sent to the webextention!?\nfunc webSocketReader(ws *websocket.Conn) {\n\tdefer ws.Close()\n\tfor {\n\t\t_, message, err := ws.ReadMessage()\n\t\thandleWebextensionCommand(message)","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/browsh-org/browsh/blob/499ef386d45cd1e2b5457dd04887c017f77b7e27/interfacer/src/browsh/comms.go#L18-L54","documentation":"Browsh's interfacer runs an HTTP/WebSocket server (on `browsh.websocket-port`, default 3333) that the Web Extension connects to. `startWebSocketServer` calls `http.ListenAndServe`; if it returns an error, browsh shuts down wrapping it with this message. In practice this is almost always a port conflict or permission problem.","triggerScenarios":"`TTYStart` or `HTTPServerStart` invokes `startWebSocketServer`; `http.ListenAndServe(\":\"+port, mux)` fails because the port is already bound (another browsh/websocket server), is privileged (<1024), or the configured port value is invalid.","commonSituations":"A previous browsh instance still running and holding port 3333; another app using the configured port; `browsh.websocket-port` misconfigured in the .toml; running in a container without the port exposed/permitted.","solutions":["Check what holds the port: `lsof -i :3333` (or your configured port) and kill the stale process.","Change the port: set `browsh.websocket-port = <free-port>` in your browsh config.","Verify no firewall/container restriction blocks binding to the port.","Restart cleanly so no orphaned browsh keeps the websocket port bound."],"exampleFix":"// before (config .toml)\nwebsocket-port = \"3333\"  # already in use\n// after\nwebsocket-port = \"3334\"","handlingStrategy":"validation","validationCode":"const net = require('net');\nconst port = 3333; // browsh.websocket-port\nconst probe = net.createServer();\nprobe.once('error', () => { throw new Error(`Port ${port} already in use`); });\nprobe.listen(port, () => { probe.close(() => console.log('port free')); });","typeGuard":null,"tryCatchPattern":"try {\n  startBrowsh();\n} catch (e) {\n  if (/Error starting websocket server/.test(e.message)) {\n    console.error('Free the port or change browsh.websocket-port:', e.message);\n  } else { throw e; }\n}","preventionTips":["Check `lsof -i :3333` before starting browsh.","Set a unique browsh.websocket-port per instance.","Ensure containers expose/allow the configured port.","Cleanly terminate previous browsh runs so the port is released."],"tags":["websocket","port-in-use","network","startup"],"backgroundTag":"port-already-in-use","analyzedSha":"499ef386d45cd1e2b5457dd04887c017f77b7e27","analyzedAt":"2026-09-02T19:05:32.228Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T21:17:11.164Z"}