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

  1. Await transport.stop() before start() when restarting the same instance
  2. Create a fresh WebSocketTransport via createWebSocketTransport(logger, cfg) per lifecycle
  3. 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

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


AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18). Data as JSON: /api/errors/6eede3dd1b9d4d95. Report an issue: GitHub.