{"record":{"id":"77103a7b3c2a31d0","repo":"ruvnet/ruflo","slug":"batch-would-exceed-maximum-concurrent-agents","errorCode":null,"errorMessage":"Batch would exceed maximum concurrent agents","messagePattern":"Batch would exceed maximum concurrent agents","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/shared/src/core/orchestrator/lifecycle-manager.ts","lineNumber":141,"sourceCode":"\n    // Mark as active\n    agent.status = 'active';\n\n    this.eventBus.emit(SystemEventTypes.AGENT_SPAWNED, {\n      agentId: agent.id,\n      profile: config,\n      sessionId: undefined,\n    });\n\n    return agent;\n  }\n\n  async spawnBatch(configs: IAgentConfig[]): Promise<Map<string, IAgent>> {\n    const results = new Map<string, IAgent>();\n\n    // Check total capacity\n    if (this.pool.size() + configs.length > this.config.maxConcurrentAgents) {\n      throw new Error('Batch would exceed maximum concurrent agents');\n    }\n\n    // Spawn in parallel\n    const spawnPromises = configs.map(async config => {\n      try {\n        const agent = await this.spawn(config);\n        return { id: config.id, agent, error: null };\n      } catch (error) {\n        return { id: config.id, agent: null, error };\n      }\n    });\n\n    const settled = await Promise.allSettled(spawnPromises);\n\n    for (const result of settled) {\n      if (result.status === 'fulfilled' && result.value.agent) {\n        results.set(result.value.id, result.value.agent);\n      }","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/shared/src/core/orchestrator/lifecycle-manager.ts#L123-L159","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nawait lifecycle.spawnBatch(allConfigs); // throws: batch would exceed cap\n\n// after\nconst free = lifecycleConfig.maxConcurrentAgents - lifecycle.getAllAgents().length;\nfor (let i = 0; i < allConfigs.length; i += free) {\n  await lifecycle.spawnBatch(allConfigs.slice(i, i + free));\n}","handlingStrategy":"validation","validationCode":"const cap = lifecycleConfig.maxConcurrentAgents;\nconst free = cap - lifecycle.getAllAgents().length;\nif (batchConfigs.length > free) {\n  const idle = lifecycle.getAllAgents().filter(a => a.status !== 'active');\n  await Promise.all(idle.map(a => lifecycle.terminate(a.id)));\n}\nconst chunk = Math.max(1, cap - lifecycle.getAllAgents().length);\nfor (let i = 0; i < batchConfigs.length; i += chunk) {\n  await lifecycle.spawnBatch(batchConfigs.slice(i, i + chunk));\n}","typeGuard":null,"tryCatchPattern":"try {\n  await lifecycle.spawnBatch(configs);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('maximum concurrent agents')) {\n    // free capacity (terminate finished agents), then spawn in smaller chunks\n  } else {\n    throw e;\n  }\n}","preventionTips":["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"],"tags":["agent-pool","capacity","batch-spawn","orchestration"],"backgroundTag":"resource-limit-exceeded","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}