browsh-org/browsh · critical
Error starting websocket server: %w
Error message
Error starting websocket server: %w
What it means
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.
Source
Thrown at interfacer/src/browsh/comms.go:36
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
stdinChannel = make(chan string)
IsConnectedToWebExtension = false
)
type incomingRawText struct {
RequestID string `json:"request_id"`
RawJSON string `json:"json"`
}
func startWebSocketServer() {
serverMux := http.NewServeMux()
serverMux.HandleFunc("/", webSocketServer)
port := viper.GetString("browsh.websocket-port")
slog.Info("Starting websocket server...")
if netErr := http.ListenAndServe(":"+port, serverMux); netErr != nil {
Shutdown(fmt.Errorf("Error starting websocket server: %w", netErr))
}
}
func sendMessageToWebExtension(message string) {
if !IsConnectedToWebExtension {
slog.Info("Webextension not connected. Message not sent", "message", message)
return
}
stdinChannel <- message
}
// Listen to all messages coming from the webextension
// TODO: It seems this *also* receives sent to the webextention!?
func webSocketReader(ws *websocket.Conn) {
defer ws.Close()
for {
_, message, err := ws.ReadMessage()
handleWebextensionCommand(message)View on GitHub (pinned to 499ef386d4)
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.
Example fix
// before (config .toml) websocket-port = "3333" # already in use // after websocket-port = "3334"
Defensive patterns
Strategy: validation
Validate before calling
const net = require('net');
const port = 3333; // browsh.websocket-port
const probe = net.createServer();
probe.once('error', () => { throw new Error(`Port ${port} already in use`); });
probe.listen(port, () => { probe.close(() => console.log('port free')); }); Try / catch
try {
startBrowsh();
} catch (e) {
if (/Error starting websocket server/.test(e.message)) {
console.error('Free the port or change browsh.websocket-port:', e.message);
} else { throw e; }
} Prevention
- 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.
When it happens
Trigger: `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.
Common situations: 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.
Related errors
- A headless Firefox is already running
- There appears to already be an existing Web Extension connec
- Failed to connect to Firefox's Marionette within 30 seconds
- Config file error: %s
AI-assisted analysis of browsh-org/browsh@499ef386d4 (2026-09-02).
Data as JSON: /api/errors/11fe0c408ef5a52a.
Report an issue: GitHub.