ruvnet/ruflo · error

HTTP transport already running

Error message

HTTP transport already running

What it means

HTTPTransport.start() binds an express app via createServer plus a WebSocketServer and is guarded by an internal running flag. A second start() on the same instance throws immediately: the port is already bound by the first start and the middleware/routes/sockets are already installed. stop() closes the server and resets the flag, enabling a stop-then-start restart.

Source

Thrown at v3/@claude-flow/shared/src/mcp/transport/http.ts:86

  private httpRequests = 0;
  private wsMessages = 0;

  constructor(
    private readonly logger: ILogger,
    private readonly config: HttpTransportConfig
  ) {
    super();
    this.app = express();
    this.setupMiddleware();
    this.setupRoutes();
  }

  /**
   * Start the transport
   */
  async start(): Promise<void> {
    if (this.running) {
      throw new Error('HTTP transport already running');
    }

    this.logger.info('Starting HTTP transport', {
      host: this.config.host,
      port: this.config.port,
    });

    // Create HTTP server
    this.server = createServer(this.app);

    // Create WebSocket server
    this.wss = new WebSocketServer({
      server: this.server,
      path: '/ws',
    });

    this.setupWebSocketHandlers();

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Memoize the start call: startPromise ??= transport.start()
  2. For restart flows: await transport.stop() before start() again
  3. Alternatively build a fresh HTTPTransport instance for the new lifecycle instead of restarting the old one

Example fix

// before
await transport.start();
await reloadConfig();
await transport.start(); // throws: already running

// after
await transport.start();
await reloadConfig();
await transport.stop();
await transport.start();
Defensive patterns

Strategy: validation

Validate before calling

let running = false;
async function startOnce() {
  if (running) return;
  await transport.start();
  running = true;
}
await startOnce();

Try / catch

try {
  await transport.start();
} catch (e) {
  if (e instanceof Error && /already running/.test(e.message)) return; // idempotent
  throw e;
}

Prevention

When it happens

Trigger: Calling transport.start() twice; restart-on-config-reload code that re-runs setup without stop(); an orchestrator handing the same transport instance to two modules that each start it; retry wrapper around start().

Common situations: Config hot-reload rebuilding wiring but reusing the transport object; health-check harness that starts the transport on every probe; module-level transport shared across tests.

Related errors


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