CherryHQ/cherry-studio · error · McpError
ErrorCode.InternalError
ErrorCode.InternalError
Error message
Agent not found: ${this.agentId} What it means
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.
Source
Thrown at src/main/ai/mcp/servers/agentMemory.ts:177
return await this.memorySearch(args)
default:
throw new McpError(ErrorCode.InvalidParams, `Unknown action "${action}", expected update/append/search`)
}
} catch (error) {
const message = error instanceof Error ? error.message : String(error)
logger.error(`Tool error: ${toolName}`, { agentId: this.agentId, error: message })
return {
content: [{ type: 'text' as const, text: `Error: ${message}` }],
isError: true
}
}
})
}
private async getAgentDataPath(): Promise<string> {
// Deliberate existence check: memory writes must stop once the owning agent is gone.
const agent = agentService.getAgent(this.agentId)
if (!agent) throw new McpError(ErrorCode.InternalError, `Agent not found: ${this.agentId}`)
const assertedPath = await assertAgentDataDirectory(path.dirname(this.agentDataPath), this.agentId)
if (path.resolve(assertedPath) !== path.resolve(this.agentDataPath)) {
throw new McpError(ErrorCode.InternalError, `Agent data path mismatch for ${this.agentId}`)
}
return assertedPath
}
private async assertMemoryDirectory(): Promise<string> {
const agentDataPath = await this.getAgentDataPath()
const memoryDir = path.join(agentDataPath, 'memory')
const memoryStat = await lstat(memoryDir)
if (!memoryStat.isDirectory() || memoryStat.isSymbolicLink()) {
throw new Error(`Agent memory directory must be a real directory: ${memoryDir}`)
}
return memoryDir
}
private async assertRegularFileOrMissing(filePath: string): Promise<void> {View on GitHub (pinned to 726446b54c)
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.
Example fix
// before: server outlives agent
const server = new AgentMemoryServer(deletedAgentId, path)
await server.callTool('memory', { action: 'append', text: '...' }) // throws
// after: check liveness before constructing/calling
if (!agentService.getAgent(agentId)) throw new Error('Agent gone; skip memory write')
const server = new AgentMemoryServer(agentId, path) Defensive patterns
Strategy: validation
Validate before calling
import { agentService } from '@data/services/AgentService'
// Before constructing or calling AgentMemoryServer:
if (!agentService.getAgent(agentId)) {
throw new Error(`Cannot use memory: agent ${agentId} no longer exists`)
} Try / catch
// Recommended: dispose the memory server when its agent is deleted.
agentService.on('agentDeleted', (id) => {
if (id === memoryServer.agentId) memoryServer.dispose()
}) Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12).
Data as JSON: /api/errors/0f279a6e4302289e.
Report an issue: GitHub.