ruvnet/ruflo · error

Maximum agents (${this.config.maxAgents}) reached

Error message

Maximum agents (${this.config.maxAgents}) reached

What it means

addNode() enforces the maxAgents ceiling from TopologyManagerConfig: once nodeIndex.size reaches maxAgents, further adds throw before the node is created. This is a hard capacity guard, not a queue, so the caller must free slots or raise the limit. It fires after the duplicate check and creates no partial state.

Source

Thrown at v3/@claude-flow/swarm/src/topology-manager.ts:73

    this.emit('initialized', { type: this.config.type });
  }

  getState(): TopologyState {
    return {
      ...this.state,
      nodes: [...this.state.nodes],
      edges: [...this.state.edges],
      partitions: [...this.state.partitions],
    };
  }

  async addNode(agentId: string, role: TopologyNode['role']): Promise<TopologyNode> {
    if (this.nodeIndex.has(agentId)) {
      throw new Error(`Node ${agentId} already exists in topology`);
    }

    if (this.nodeIndex.size >= this.config.maxAgents) {
      throw new Error(`Maximum agents (${this.config.maxAgents}) reached`);
    }

    // Create node with connections based on topology type
    const connections = this.calculateInitialConnections(agentId, role);

    const node: TopologyNode = {
      id: `node_${agentId}`,
      agentId,
      role: this.determineRole(role),
      status: 'syncing',
      connections,
      metadata: {
        joinedAt: new Date().toISOString(),
        version: '1.0.0',
      },
    };

    // Add to state

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Raise maxAgents in the topology config passed to TopologyManager.initialize so it covers the planned fleet size
  2. removeNode() for dead or stale agents to free slots before adding new ones
  3. In spawn loops, check current node count against maxAgents before each add

Example fix

// before
const topology = new TopologyManager({ type: 'mesh', maxAgents: 8 });
await Promise.all(agentIds.map(id => topology.addNode(id, 'worker'))); // throws once size hits 8

// after
const topology = new TopologyManager({ type: 'mesh', maxAgents: agentIds.length + 4 });
await Promise.all(agentIds.map(id => topology.addNode(id, 'worker')));
Defensive patterns

Strategy: validation

Validate before calling

function hasCapacity(topology: TopologyManager, maxAgents: number): boolean {
  return topology.getState().nodes.length < maxAgents;
}

if (!hasCapacity(topology, config.maxAgents)) {
  await evictDeadNodes(topology); // removeNode for offline agents to free slots
}
await topology.addNode(agentId, 'worker');

Type guard

function hasCapacity(topology: TopologyManager, maxAgents: number): boolean {
  return topology.getState().nodes.length < maxAgents;
}

Try / catch

try {
  await topology.addNode(agentId, 'worker');
} catch (err) {
  if (err instanceof Error && err.message.includes('Maximum agents')) {
    await topology.removeNode(oldestIdleAgentId(topology));
    return topology.addNode(agentId, 'worker');
  }
  throw err;
}

Prevention

When it happens

Trigger: Scaling the fleet past config.maxAgents (for example a default of 8) via addNode; autoscaler loops that keep spawning; dead or stale nodes still occupying slots because removeNode was never called.

Common situations: Copying a topology config from a small test swarm into a larger deployment; nodes removed from the cluster but never removed from the topology; growing the fleet without touching maxAgents.

Related errors


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