ruvnet/ruflo · error · Error
Worker ${config.id} already exists in pool
Error message
Worker ${config.id} already exists in pool What it means
WorkerPool.spawn rejects a config.id that already exists in the pool unless options.replace is set; with replace the old worker is terminated first, otherwise the duplicate throws. Worker ids are the pool's identity key.
Source
Thrown at v3/@claude-flow/integration/src/worker-pool.ts:325
* @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,
};
// Create appropriate worker type
let worker: WorkerBase;
if ('domain' in config) {
worker = new SpecializedWorker(config as SpecializedWorkerConfig);
} else if ('checkpointInterval' in config) {
worker = new LongRunningWorker(config as LongRunningWorkerConfig);
} else {
// Create a concrete implementation for generic workersView on GitHub (pinned to fa13ee4ad6)
Solutions
- Pass { replace: true } when re-spawning is meant to swap the old worker
- Otherwise terminate(config.id) first, or pick a fresh unique id (uuid suffix)
- Deduplicate worker configs before applying them — ids should be unique by construction
Example fix
// before
pool.spawn({ id: 'coder-1', type: 'coder' });
pool.spawn({ id: 'coder-1', type: 'coder' }); // throws: duplicate
// after
pool.spawn({ id: 'coder-1', type: 'coder' }, { replace: true }); // intentional swap Defensive patterns
Strategy: validation
Validate before calling
// Guard spawns against id collisions
const spawnedIds = new Set<string>();
function spawnUnique(cfg: WorkerConfig, replace = false) {
if (spawnedIds.has(cfg.id) && !replace) {
throw new Error(`worker id ${cfg.id} already spawned`);
}
const w = replace ? pool.spawn(cfg, { replace: true }) : pool.spawn(cfg);
spawnedIds.add(cfg.id);
return w;
} Type guard
const isUniqueWorkerId = (id: string, taken: Set<string>): boolean => !taken.has(id);
Try / catch
try {
pool.spawn(cfg);
} catch (e) {
if (e instanceof Error && e.message.includes('already exists in pool')) {
// decide: swap (spawn with { replace: true }) or regenerate the id — never ignore
}
throw e;
} Prevention
- Generate ids (uuid) instead of stable names when re-spawns are possible
- Apply worker config sets idempotently: skip ids already present
- Log every spawn/terminate pair so duplicate ids are traceable
When it happens
Trigger: Spawning a worker whose id is already present (this.workers.has(config.id)) without { replace: true } — typical with deterministic ids like 'coder-1' reused across restart or re-spawn cycles.
Common situations: Crash-recovery logic re-spawning by stable name; config files listing worker ids re-applied without dedupe; multiple components each spawning a well-known id that collides.
Related errors
- Pool ${this.id} at maximum capacity (${this.config.maxWorker
- Invalid completion type
- MCP server "${server.name}" returned HTTP ${httpStatus}: ${h
- No endpoints configured. This build requires OpenAI-compatib
- Only 'openai' endpoint type is supported in this build
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/fffc0eb9fe32aba2.
Report an issue: GitHub.