ruvnet/ruflo · error
Pool ${this.id} at maximum capacity (${this.config.maxWorker
Error message
Pool ${this.id} at maximum capacity (${this.config.maxWorkers} workers) What it means
WorkerPool.spawn enforces config.maxWorkers: once workers.size reaches the cap, further spawns throw unless options.replace is set. The pool never silently evicts workers to make room.
Source
Thrown at v3/@claude-flow/integration/src/worker-pool.ts:315
this.initialized = false;
this.emit('pool-shutdown', { poolId: this.id });
}
/**
* Spawn a new worker in the pool
*
* @param config - Worker configuration
* @param options - Spawn options
* @returns Created worker
*/
spawn(
config: WorkerConfig | SpecializedWorkerConfig | LongRunningWorkerConfig,
options: SpawnOptions = {}
): WorkerBase {
// Check capacity
if (this.workers.size >= this.config.maxWorkers! && !options.replace) {
throw new Error(
`Pool ${this.id} at maximum capacity (${this.config.maxWorkers} workers)`
);
}
// Handle replacement
if (this.workers.has(config.id)) {
if (options.replace) {
this.terminate(config.id);
} else {
throw new Error(`Worker ${config.id} already exists in pool`);
}
}
// Merge with default config
const mergedConfig = {
...this.config.defaultWorkerConfig,
...config,
};View on GitHub (pinned to fa13ee4ad6)
Solutions
- Terminate an expendable worker first (pool.terminate(id)) to free a slot, then spawn
- Pass { replace: true } when the spawn is intentionally swapping an existing worker
- Raise config.maxWorkers if the workload legitimately needs more
Example fix
// before
for (let i = 0; i < 10; i++) pool.spawn({ id: `w${i}`, type: 'coder' }); // maxWorkers=4 -> 5th call throws
// after
pool.terminate(idleWorkerId()); // free a slot before hitting the cap
pool.spawn({ id: 'w5', type: 'coder' }); Defensive patterns
Strategy: validation
Validate before calling
// Track pool occupancy via your own spawn/terminate accounting
const spawnedIds = new Set<string>();
function spawnWithHeadroom(cfg: WorkerConfig, maxWorkers: number) {
if (spawnedIds.size >= maxWorkers) {
pool.terminate(pickIdleWorkerId()); // free a slot first
spawnedIds.delete(pickIdleWorkerId());
}
const w = pool.spawn(cfg);
spawnedIds.add(cfg.id);
return w;
} Try / catch
try {
pool.spawn(cfg);
} catch (e) {
if (e instanceof Error && /maximum capacity/.test(e.message)) {
// evict an idle worker and retry once, or reject the load — do not loop spawning
}
throw e;
} Prevention
- Size maxWorkers from measured peak load, not average
- Make autoscalers terminate-before-spawn at the cap
- Expose pool occupancy in dashboards so spawns never surprise the cap
When it happens
Trigger: Spawning a new worker when the pool already holds maxWorkers entries and SpawnOptions.replace is not true.
Common situations: An autoscaler spawning on demand without terminating idle workers first; a fixed pool sized too small for peak load; scale-up logic that ignores the configured cap.
Related errors
- Worker ${config.id} already exists in pool
- Maximum sessions (${this.config.maxSessions}) reached
- Maximum agents (${this.config.maxAgents}) reached
- Invalid completion type
- MCP server "${server.name}" returned HTTP ${httpStatus}: ${h
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/b1695cd160f079d1.
Report an issue: GitHub.