ruvnet/ruflo · error · Error
WebSocket transport already running
Error message
WebSocket transport already running
What it means
WebSocketTransport.start() creates the HTTP upgrade server and flips a private `running` flag; a second start() on the same instance throws 'WebSocket transport already running'. As with the other transports, only stop() resets the flag, so the error means the same object was started twice in its lifecycle.
Source
Thrown at v3/@claude-flow/mcp/src/transport/websocket.ts:71
private heartbeatTimer?: NodeJS.Timeout;
private running = false;
private connectionCounter = 0;
private messagesReceived = 0;
private messagesSent = 0;
private errors = 0;
private totalConnections = 0;
constructor(
private readonly logger: ILogger,
private readonly config: WebSocketTransportConfig
) {
super();
}
async start(): Promise<void> {
if (this.running) {
throw new Error('WebSocket transport already running');
}
this.logger.info('Starting WebSocket transport', {
host: this.config.host,
port: this.config.port,
path: this.config.path || '/ws',
});
this.server = createServer((req, res) => {
res.writeHead(426, { 'Content-Type': 'text/plain' });
res.end('Upgrade Required - WebSocket connection expected');
});
this.wss = new WebSocketServer({
server: this.server,
path: this.config.path || '/ws',
maxPayload: this.config.maxMessageSize || 10 * 1024 * 1024,
perMessageDeflate: true,View on GitHub (pinned to fa13ee4ad6)
Solutions
- Await transport.stop() before start() when restarting the same instance
- Create a fresh WebSocketTransport via createWebSocketTransport(logger, cfg) per lifecycle
- Let TransportManager own the lifecycle (startAll/stopAll) instead of manual start calls
Example fix
// before
await wsTransport.start();
await wsTransport.start(); // throws
// after
async function restart(t: ITransport) {
await t.stop();
await t.start();
} Defensive patterns
Strategy: validation
Validate before calling
// WebSocketTransport.running is private; guard at the call site
let wsStarted = false;
async function ensureWsStarted(t: ITransport) {
if (wsStarted) return;
await t.start();
wsStarted = true;
} Try / catch
try {
await wsTransport.start();
} catch (e) {
if (e instanceof Error && e.message === 'WebSocket transport already running') {
// already up - no-op
} else {
throw e;
}
} Prevention
- Reconnect logic should check state or stop() first, never blind-start
- Prefer TransportManager.startAll()/stopAll() for lifecycle ownership
- In watch mode, recreate transport instances instead of reusing module singletons
When it happens
Trigger: Calling start() from bootstrap and from a reconnect handler; hot-reload re-running init with a surviving singleton; startAll() followed by a manual transport.start() on the same instance.
Common situations: Reconnect logic that calls start() instead of checking state; tests that start in both setup and body; module-level singletons under watch mode.
Related errors
- HTTP transport already running
- WebSocket transport already running
- WebSocket transport requires host and port configuration
- Transport "${name}" already exists
- TransportManager already running
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/6eede3dd1b9d4d95.
Report an issue: GitHub.