{"record":{"id":"b2fbb978428dbb88","repo":"ruvnet/ruflo","slug":"agent-not-found-agentid-b2fbb9","errorCode":null,"errorMessage":"Agent not found: ${agentId}","messagePattern":"Agent not found: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/shared/src/core/orchestrator/lifecycle-manager.ts","lineNumber":168,"sourceCode":"        return { id: config.id, agent: null, error };\n      }\n    });\n\n    const settled = await Promise.allSettled(spawnPromises);\n\n    for (const result of settled) {\n      if (result.status === 'fulfilled' && result.value.agent) {\n        results.set(result.value.id, result.value.agent);\n      }\n    }\n\n    return results;\n  }\n\n  async terminate(agentId: string, reason?: string): Promise<void> {\n    const agent = this.pool.get(agentId);\n    if (!agent) {\n      throw new Error(`Agent not found: ${agentId}`);\n    }\n\n    agent.status = 'terminated';\n\n    // Remove from pool\n    this.pool.remove(agentId);\n\n    this.eventBus.emit(SystemEventTypes.AGENT_TERMINATED, {\n      agentId,\n      reason: reason ?? 'User requested',\n    });\n  }\n\n  async terminateAll(reason?: string): Promise<void> {\n    const agents = this.pool.getAll();\n    await Promise.allSettled(\n      agents.map(agent => this.terminate(agent.id, reason)),\n    );","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/shared/src/core/orchestrator/lifecycle-manager.ts#L150-L186","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check lifecycle.getAgent(agentId) before calling terminate() and treat undefined as already-removed","Make shutdown idempotent: wrap terminate() in try-catch and ignore 'Agent not found' during teardown","If the agent should exist, verify you are calling the same LifecycleManager instance that spawned it"],"exampleFix":"// before\nawait lifecycle.terminate(agentId);\n\n// after\nif (lifecycle.getAgent(agentId)) {\n  await lifecycle.terminate(agentId);\n}","handlingStrategy":"validation","validationCode":"if (!lifecycle.getAgent(agentId)) {\n  // already removed or never spawned; nothing to terminate\n  return;\n}\nawait lifecycle.terminate(agentId, reason);","typeGuard":"function isLiveAgent(lifecycle: LifecycleManager, id: string): boolean {\n  return lifecycle.getAgent(id) !== undefined;\n}","tryCatchPattern":"try {\n  await lifecycle.terminate(agentId);\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Agent not found')) return; // idempotent teardown\n  throw e;\n}","preventionTips":["Check getAgent(id) before every terminate() call","Make shutdown paths idempotent and tolerate 'Agent not found'","Remember the pool is in-memory: never reuse IDs across process restarts"],"tags":["agent","not-found","lifecycle","termination"],"backgroundTag":"entity-not-found","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}