ruvnet/ruflo · error
Batch would exceed maximum concurrent agents
Error message
Batch would exceed maximum concurrent agents
What it means
Thrown by LifecycleManager.spawnBatch as a pre-flight capacity check: it fires when the number of agents currently in the pool plus configs.length would exceed the maxConcurrentAgents value from the LifecycleManagerConfig passed at construction. The check runs before any agent in the batch is spawned, so a failure means nothing was partially created. It keeps concurrent agent usage inside the configured ceiling.
Source
Thrown at v3/@claude-flow/shared/src/core/orchestrator/lifecycle-manager.ts:141
// Mark as active
agent.status = 'active';
this.eventBus.emit(SystemEventTypes.AGENT_SPAWNED, {
agentId: agent.id,
profile: config,
sessionId: undefined,
});
return agent;
}
async spawnBatch(configs: IAgentConfig[]): Promise<Map<string, IAgent>> {
const results = new Map<string, IAgent>();
// Check total capacity
if (this.pool.size() + configs.length > this.config.maxConcurrentAgents) {
throw new Error('Batch would exceed maximum concurrent agents');
}
// Spawn in parallel
const spawnPromises = configs.map(async config => {
try {
const agent = await this.spawn(config);
return { id: config.id, agent, error: null };
} catch (error) {
return { id: config.id, agent: null, error };
}
});
const settled = await Promise.allSettled(spawnPromises);
for (const result of settled) {
if (result.status === 'fulfilled' && result.value.agent) {
results.set(result.value.id, result.value.agent);
}View on GitHub (pinned to fa13ee4ad6)
Solutions
- Free capacity first: call getAllAgents(), terminate() finished or idle agents so pool size + batch length fits under maxConcurrentAgents
- Split the batch into chunks of at most (maxConcurrentAgents - getAllAgents().length) and spawn in waves
- Raise maxConcurrentAgents in the LifecycleManagerConfig if the workload genuinely needs more concurrent agents
- If the cap keeps firing, treat it as a scheduling signal (await running agents) rather than removing the limit
Example fix
// before
await lifecycle.spawnBatch(allConfigs); // throws: batch would exceed cap
// after
const free = lifecycleConfig.maxConcurrentAgents - lifecycle.getAllAgents().length;
for (let i = 0; i < allConfigs.length; i += free) {
await lifecycle.spawnBatch(allConfigs.slice(i, i + free));
} Defensive patterns
Strategy: validation
Validate before calling
const cap = lifecycleConfig.maxConcurrentAgents;
const free = cap - lifecycle.getAllAgents().length;
if (batchConfigs.length > free) {
const idle = lifecycle.getAllAgents().filter(a => a.status !== 'active');
await Promise.all(idle.map(a => lifecycle.terminate(a.id)));
}
const chunk = Math.max(1, cap - lifecycle.getAllAgents().length);
for (let i = 0; i < batchConfigs.length; i += chunk) {
await lifecycle.spawnBatch(batchConfigs.slice(i, i + chunk));
} Try / catch
try {
await lifecycle.spawnBatch(configs);
} catch (e) {
if (e instanceof Error && e.message.includes('maximum concurrent agents')) {
// free capacity (terminate finished agents), then spawn in smaller chunks
} else {
throw e;
}
} Prevention
- Size every batch against lifecycle.getAllAgents().length and the configured maxConcurrentAgents before calling spawnBatch
- Always terminate() agents when their work completes so the pool drains between waves
- Spawn large swarms in waves instead of a single batch
When it happens
Trigger: Calling spawnBatch(configs) while the pool already holds agents, e.g. maxConcurrentAgents: 10 with 8 live agents and a batch of 5 (8 + 5 > 10). Also hit when finished agents are never terminate()d so the pool never drains, or when swarm-init code (e.g. a hierarchical topology spawning 5-15 agents) submits a bigger batch than the configured ceiling.
Common situations: Swarm recipes spawning many agents while LifecycleManagerConfig keeps a low maxConcurrentAgents default; scaling up --max-agents on the CLI without raising the lifecycle manager's ceiling; long-running orchestrators that spawn but never terminate agents.
Related errors
- Pool ${this.id} at maximum capacity (${this.config.maxWorker
- Max sessions (${this.config.maxSessions}) reached
- worker dependency cycle: ${remaining.join(', ')}
- writer ${worker.id} requires an isolated worktree
- concurrent writers must use distinct worktrees: ${writerPath
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/77103a7b3c2a31d0.
Report an issue: GitHub.