ruvnet/ruflo · error

Maximum sessions (${this.config.maxSessions}) reached

Error message

Maximum sessions (${this.config.maxSessions}) reached

What it means

MCPSessionManager caps concurrent sessions at config.maxSessions (merged over DEFAULT_SESSION_CONFIG in the constructor, which also starts a cleanup timer). createSession() throws when sessions.size has reached the cap, bounding per-process memory. Slots are only freed when sessions are removed on disconnect/close or reclaimed by the cleanup timer after timeout. The manager exposes getActiveSessions() and getSessionMetrics() for monitoring.

Source

Thrown at v3/@claude-flow/shared/src/mcp/session-manager.ts:81

  private totalClosed = 0;
  private totalExpired = 0;

  constructor(
    private readonly logger: ILogger,
    config: SessionConfig = {}
  ) {
    super();
    this.config = { ...DEFAULT_SESSION_CONFIG, ...config };
    this.startCleanupTimer();
  }

  /**
   * Create a new session
   */
  createSession(transport: TransportType): MCPSession {
    // Check max sessions
    if (this.sessions.size >= this.config.maxSessions) {
      throw new Error(`Maximum sessions (${this.config.maxSessions}) reached`);
    }

    const id = this.generateSessionId();
    const now = new Date();

    const session: MCPSession = {
      id,
      state: 'created',
      transport,
      createdAt: now,
      lastActivityAt: now,
      isInitialized: false,
      isAuthenticated: false,
    };

    this.sessions.set(id, session);
    this.totalCreated++;

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Raise maxSessions in the SessionManager config to match real concurrency (and confirm it in code, not just docs)
  2. Free stuck slots: close stale sessions explicitly, or shorten the timeout config so the cleanup timer reclaims abandoned sessions faster
  3. Fix client-side leaks so every connection disconnects cleanly (finally/close handlers)
  4. If load is legitimate, run more server processes and load-balance instead of raising the cap unboundedly

Example fix

// before
const manager = new MCPSessionManager(); // default cap; throws under load

// after
const manager = new MCPSessionManager({
  maxSessions: 500,
});
// monitor before it saturates:
setInterval(() => console.log(manager.getActiveSessions().length), 30_000);
Defensive patterns

Strategy: validation

Validate before calling

const MAX_SESSIONS = 500; // keep in sync with the manager config
if (manager.getActiveSessions().length >= MAX_SESSIONS) {
  return respond503(); // shed load at the edge instead of letting createSession throw
}
const session = manager.createSession(transportType);

Try / catch

try {
  const session = manager.createSession(transportType);
} catch (e) {
  if (e instanceof Error && /Maximum sessions/.test(e.message)) {
    return respond503WithRetryAfter(30); // capacity: back off, do not crash the handler
  }
  throw e;
}

Prevention

When it happens

Trigger: More clients connecting via http/ws/stdio transports than maxSessions, without disconnecting; leaked sessions where a connection was created but initialize never completed and never closed; load tests spawning many short-lived clients; maxSessions configured below expected concurrency.

Common situations: Default cap too low for production traffic; clients crashing without closing so sessions linger until timeout; test suites sharing one manager with a small cap; forgetting to scale horizontally so a single process absorbs all connections.

Related errors


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