ruvnet/ruflo · error
Agent ${agentId} not found
Error message
Agent ${agentId} not found What it means
terminateAgent() looks up agentId in the agents map and throws when absent. Ids match exactly what spawnAgent() returned (explicit or agent-N form); there is no normalization. Because terminated agents remain in the map, terminating an already-terminated id does NOT throw — the throw means the id was never spawned (or belongs to another integration instance).
Source
Thrown at v3/@claude-flow/plugins/src/integrations/agentic-flow.ts:257
this.agents.set(id, agent);
this.emit(AGENTIC_FLOW_EVENTS.AGENT_SPAWNED, {
agent,
timestamp: new Date(),
});
this.config.logger?.info(`Agent spawned: ${id} (${options.type})`);
return agent;
}
/**
* Terminate an agent.
*/
async terminateAgent(agentId: string): Promise<void> {
const agent = this.agents.get(agentId);
if (!agent) {
throw new Error(`Agent ${agentId} not found`);
}
// Update agent status
const terminatedAgent: SpawnedAgent = { ...agent, status: 'terminated' };
this.agents.set(agentId, terminatedAgent);
this.emit(AGENTIC_FLOW_EVENTS.AGENT_TERMINATED, {
agentId,
timestamp: new Date(),
});
this.config.logger?.info(`Agent terminated: ${agentId}`);
}
/**
* Get agent by ID.
*/
getAgent(agentId: string): SpawnedAgent | undefined {View on GitHub (pinned to fa13ee4ad6)
Solutions
- Always use the SpawnedAgent.id captured from spawnAgent(); never reconstruct ids by string concatenation
- Route termination through a guard that treats 'not found' as already-gone success in cleanup code
- Keep one registry (Map<string, SpawnedAgent>) of live agents per integration and terminate only from it
Example fix
// before
await flow.terminateAgent(agentIdFromSomewhere); // Error: Agent ... not found
// after (cleanup-safe)
try {
await flow.terminateAgent(agentId);
} catch (err) {
if (!(err instanceof Error && /Agent .* not found/.test(err.message))) throw err;
// already gone: nothing to do
} Defensive patterns
Strategy: validation
Validate before calling
const live = new Map<string, SpawnedAgent>();
async function safeTerminate(id: string): Promise<void> {
if (!live.has(id)) return; // already gone / never spawned: no-op
await flow.terminateAgent(id);
live.delete(id);
} Try / catch
try {
await flow.terminateAgent(agentId);
} catch (err) {
if (err instanceof Error && /Agent .* not found/.test(err.message)) {
// treat as already-terminated in cleanup paths
} else {
throw err;
}
} Prevention
- Always terminate with the SpawnedAgent.id returned by spawnAgent()
- Never reconstruct auto ids by string concatenation
- Make cleanup idempotent: tolerate not-found instead of failing teardown
When it happens
Trigger: Terminating with a typo'd or case-different id; reconstructing auto ids by string building ('agent-2') instead of using the returned SpawnedAgent.id; ids crossing serialization boundaries (JSON round-trip trimming); cleanup running after agents were spawned on a different instance.
Common situations: Shutdown handlers draining agents recorded from a previous run or another process; logs replayed into terminate calls; tests constructing a fresh integration but terminating ids from an earlier one.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Swarm not initialized
- Maximum agent limit (${this.config.maxConcurrentAgents}) rea
- Agent ${id} already exists
- No available agents
- Max sessions (${this.config.maxSessions}) reached
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/21dcae58e3b13bbe.
Report an issue: GitHub.