{"record":{"id":"0f279a6e4302289e","repo":"CherryHQ/cherry-studio","slug":"errorcode-internalerror","errorCode":"ErrorCode.InternalError","errorMessage":"Agent not found: ${this.agentId}","messagePattern":"Agent not found: (.+?)","errorType":"exception","errorClass":"McpError","httpStatus":null,"severity":"error","filePath":"src/main/ai/mcp/servers/agentMemory.ts","lineNumber":177,"sourceCode":"            return await this.memorySearch(args)\n          default:\n            throw new McpError(ErrorCode.InvalidParams, `Unknown action \"${action}\", expected update/append/search`)\n        }\n      } catch (error) {\n        const message = error instanceof Error ? error.message : String(error)\n        logger.error(`Tool error: ${toolName}`, { agentId: this.agentId, error: message })\n        return {\n          content: [{ type: 'text' as const, text: `Error: ${message}` }],\n          isError: true\n        }\n      }\n    })\n  }\n\n  private async getAgentDataPath(): Promise<string> {\n    // Deliberate existence check: memory writes must stop once the owning agent is gone.\n    const agent = agentService.getAgent(this.agentId)\n    if (!agent) throw new McpError(ErrorCode.InternalError, `Agent not found: ${this.agentId}`)\n    const assertedPath = await assertAgentDataDirectory(path.dirname(this.agentDataPath), this.agentId)\n    if (path.resolve(assertedPath) !== path.resolve(this.agentDataPath)) {\n      throw new McpError(ErrorCode.InternalError, `Agent data path mismatch for ${this.agentId}`)\n    }\n    return assertedPath\n  }\n\n  private async assertMemoryDirectory(): Promise<string> {\n    const agentDataPath = await this.getAgentDataPath()\n    const memoryDir = path.join(agentDataPath, 'memory')\n    const memoryStat = await lstat(memoryDir)\n    if (!memoryStat.isDirectory() || memoryStat.isSymbolicLink()) {\n      throw new Error(`Agent memory directory must be a real directory: ${memoryDir}`)\n    }\n    return memoryDir\n  }\n\n  private async assertRegularFileOrMissing(filePath: string): Promise<void> {","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/mcp/servers/agentMemory.ts#L159-L195","documentation":"getAgentDataPath() is the gate every memory write/read must pass. It calls agentService.getAgent(this.agentId) and throws McpError InternalError if the agent no longer exists. The comment on line 175 states this is deliberate: memory writes must stop once the owning agent is gone, preventing orphaned data writes to a deleted agent's directory.","triggerScenarios":"The agent was deleted via the UI or agentService while an MCP session/tool call was in flight; the agentId passed to the AgentMemoryServer constructor was never valid or pointed to a different agent; a stale MCP server instance outlived its agent.","commonSituations":"User deletes an agent during an active conversation; a race between agent deletion and an in-flight memory tool call; agent data was migrated or the agent id changed.","solutions":["Verify the agent still exists before issuing memory tool calls (agentService.getAgent(id)).","Tear down the MCP server when its agent is deleted so no stale calls reach it.","If the agent was deleted intentionally, no action is needed — the error is the correct behavior."],"exampleFix":"// before: server outlives agent\nconst server = new AgentMemoryServer(deletedAgentId, path)\nawait server.callTool('memory', { action: 'append', text: '...' }) // throws\n\n// after: check liveness before constructing/calling\nif (!agentService.getAgent(agentId)) throw new Error('Agent gone; skip memory write')\nconst server = new AgentMemoryServer(agentId, path)","handlingStrategy":"validation","validationCode":"import { agentService } from '@data/services/AgentService'\n\n// Before constructing or calling AgentMemoryServer:\nif (!agentService.getAgent(agentId)) {\n  throw new Error(`Cannot use memory: agent ${agentId} no longer exists`)\n}","typeGuard":null,"tryCatchPattern":"// Recommended: dispose the memory server when its agent is deleted.\nagentService.on('agentDeleted', (id) => {\n  if (id === memoryServer.agentId) memoryServer.dispose()\n})","preventionTips":["Tie MCP server lifetime to agent lifetime — dispose the server when the agent is deleted.","Check agentService.getAgent(id) before issuing memory tool calls.","Treat this InternalError as expected (not a bug) when it follows a deliberate deletion."],"tags":["mcp","lifecycle","agent-memory","internal-error","stale-reference"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}