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 workers

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Pass { replace: true } when re-spawning is meant to swap the old worker
  2. Otherwise terminate(config.id) first, or pick a fresh unique id (uuid suffix)
  3. 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

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


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