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
- Raise maxSessions in the SessionManager config to match real concurrency (and confirm it in code, not just docs)
- Free stuck slots: close stale sessions explicitly, or shorten the timeout config so the cleanup timer reclaims abandoned sessions faster
- Fix client-side leaks so every connection disconnects cleanly (finally/close handlers)
- 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
- Monitor getActiveSessions().length against the cap and alert before saturation
- Always close sessions in finally blocks on the client side
- Tune session timeout config so abandoned sessions free slots quickly
- Return 503/backpressure at the edge rather than letting createSession throw mid-request
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
- MCP server "${server.name}" returned HTTP ${httpStatus}: ${h
- Key exceeds maximum length of ${MAX_KEY_LENGTH} characters
- Value exceeds maximum size of ${MAX_VALUE_SIZE} bytes
- Query exceeds maximum length of ${MAX_QUERY_LENGTH} characte
- namespace exceeds 128 characters
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/93c7f342601ed189.
Report an issue: GitHub.