ruvnet/ruflo · error

Maximum agent limit (${this.config.maxConcurrentAgents}) rea

Error message

Maximum agent limit (${this.config.maxConcurrentAgents}) reached

What it means

spawnAgent() caps concurrent agents at config.maxConcurrentAgents (default 15), counting every entry in the agents map. Importantly, terminateAgent() only flips status to 'terminated' and keeps the entry in the map, so terminated agents still consume slots — the limit is reached on total registered agents, not live ones.

Source

Thrown at v3/@claude-flow/plugins/src/integrations/agentic-flow.ts:221

    this.swarmInitialized = false;
    this.swarmTopology = undefined;
    this.config.logger?.info('Swarm shutdown complete');
  }

  // =========================================================================
  // Agent Management
  // =========================================================================

  /**
   * Spawn a new agent.
   */
  async spawnAgent(options: AgentSpawnOptions): Promise<SpawnedAgent> {
    if (!this.swarmInitialized) {
      throw new Error('Swarm not initialized');
    }

    if (this.agents.size >= (this.config.maxConcurrentAgents ?? 15)) {
      throw new Error(`Maximum agent limit (${this.config.maxConcurrentAgents}) reached`);
    }

    const id = options.id ?? `agent-${this.nextAgentId++}`;

    if (this.agents.has(id)) {
      throw new Error(`Agent ${id} already exists`);
    }

    const agent: SpawnedAgent = {
      id,
      type: options.type,
      status: 'active',
      capabilities: options.capabilities ?? [],
      parentId: options.parentId,
      spawnedAt: new Date(),
    };

    this.agents.set(id, agent);

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Set config.maxConcurrentAgents to your intended pool size when constructing the integration
  2. Reuse existing active/idle agents (orchestrateTask without agentId auto-picks one) instead of spawning per task
  3. Size spawn counts against the cap you configured, accounting for terminated-but-present entries

Example fix

// before
const flow = new AgenticFlowIntegration({ logger }); // default cap 15
for (let i = 0; i < 30; i++) await flow.spawnAgent({ type: 'coder' }); // throws at #16

// after
const flow = new AgenticFlowIntegration({ logger, maxConcurrentAgents: 30 });
for (let i = 0; i < 30; i++) await flow.spawnAgent({ type: 'coder' });
Defensive patterns

Strategy: validation

Validate before calling

const MAX = 30;
const spawned = new Set<string>();
async function safeSpawn(opts: AgentSpawnOptions): Promise<SpawnedAgent> {
  if (spawned.size >= MAX) {
    throw new Error(`agent budget exhausted (${MAX}); terminate or raise maxConcurrentAgents`);
  }
  const agent = await flow.spawnAgent(opts);
  spawned.add(agent.id);
  return agent;
}
// construct with matching cap: new AgenticFlowIntegration({ maxConcurrentAgents: MAX })

Prevention

When it happens

Trigger: Spawning the 16th agent with the default cap; bulk-spawning a worker pool larger than maxConcurrentAgents; repeatedly spawn/terminate cycles that never free slots because terminated entries remain in the map.

Common situations: Workloads sized above the default 15 agents; forgetting to raise maxConcurrentAgents in the integration config; assuming termination frees capacity when it does not.

Related errors


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