ruvnet/ruflo · error

Agent not found: ${agentId}

Error message

Agent not found: ${agentId}

What it means

LifecycleManager.terminate() resolves the agent through pool.get(agentId) and throws when the lookup returns undefined. The pool is an in-memory Map with no persistence, so the ID was either never spawned by this manager instance or was already removed by an earlier terminate(). This guard is the standard failure mode for lifecycle operations on unknown agents.

Source

Thrown at v3/@claude-flow/shared/src/core/orchestrator/lifecycle-manager.ts:168

        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);
      }
    }

    return results;
  }

  async terminate(agentId: string, reason?: string): Promise<void> {
    const agent = this.pool.get(agentId);
    if (!agent) {
      throw new Error(`Agent not found: ${agentId}`);
    }

    agent.status = 'terminated';

    // Remove from pool
    this.pool.remove(agentId);

    this.eventBus.emit(SystemEventTypes.AGENT_TERMINATED, {
      agentId,
      reason: reason ?? 'User requested',
    });
  }

  async terminateAll(reason?: string): Promise<void> {
    const agents = this.pool.getAll();
    await Promise.allSettled(
      agents.map(agent => this.terminate(agent.id, reason)),
    );

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Check lifecycle.getAgent(agentId) before calling terminate() and treat undefined as already-removed
  2. Make shutdown idempotent: wrap terminate() in try-catch and ignore 'Agent not found' during teardown
  3. If the agent should exist, verify you are calling the same LifecycleManager instance that spawned it

Example fix

// before
await lifecycle.terminate(agentId);

// after
if (lifecycle.getAgent(agentId)) {
  await lifecycle.terminate(agentId);
}
Defensive patterns

Strategy: validation

Validate before calling

if (!lifecycle.getAgent(agentId)) {
  // already removed or never spawned; nothing to terminate
  return;
}
await lifecycle.terminate(agentId, reason);

Type guard

function isLiveAgent(lifecycle: LifecycleManager, id: string): boolean {
  return lifecycle.getAgent(id) !== undefined;
}

Try / catch

try {
  await lifecycle.terminate(agentId);
} catch (e) {
  if (e instanceof Error && e.message.startsWith('Agent not found')) return; // idempotent teardown
  throw e;
}

Prevention

When it happens

Trigger: Calling terminate(agentId) twice (the first call already did pool.remove); passing an ID produced by a different LifecycleManager instance or a previous process run; racing terminateAll() against terminate() for the same agent; a typo'd or stale ID.

Common situations: Double-termination in cleanup paths (e.g. both a test afterEach hook and explicit shutdown); storing agent IDs externally and reusing them after a service restart; concurrent shutdown handlers racing each other.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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