CherryHQ/cherry-studio · error · McpError

InternalError

InternalError

Error message

Failed to ensure memory path: ${error instanceof Error ? error.message : String(error)}

What it means

Thrown by KnowledgeGraphManager._ensureMemoryPathExists (memory.ts:57) as an McpError with ErrorCode.InternalError when either fs.mkdir of the memory file's parent directory fails, or the subsequent fs.access/fs.writeFile of the initial empty {entities:[],relations:[]} structure fails. The underlying Error.message (or String fallback) is appended. This runs during KnowledgeGraphManager.create and propagates to _initializeManager, which sets knowledgeGraphManager=null.

Solutions

  1. Check the resolved memoryPath and ensure its parent directory is writable by the app process.
  2. Free disk space or move the memory_file path to a writable location via configuration.
  3. Inspect the underlying error.message for the errno (EACCES/EROFS/ENOTDIR) to target the fix.
  4. Verify application.getPath('feature.mcp.memory_file') returns the intended absolute path and the namespace is registered.

Example fix

// before: memory_file resolves to a read-only dir
// ensureMemoryPath throws: Failed to ensure memory path: EROFS

// after: configure a writable path
application.getPath // ensure 'feature.mcp.memory_file' -> '<userData>/memory/memory.json' on a writable volume
Defensive patterns

Strategy: try-catch

Validate before calling

import fs from 'fs/promises'
async function ensureMemoryWritable(memoryPath: string): Promise<void> {
  const dir = path.dirname(memoryPath)
  await fs.mkdir(dir, { recursive: true })
  await fs.access(dir, fs.constants.W_OK)
}

Try / catch

try {
  await KnowledgeGraphManager.create(memoryPath)
} catch (e) {
  if (e instanceof McpError && e.code === ErrorCode.InternalError && e.message.startsWith('Failed to ensure memory path')) {
    // fix the path/permissions, then re-create the manager
  } else throw e
}

Prevention

When it happens

Trigger: The memory file path (from application.getPath('feature.mcp.memory_file') or an env path) points at a parent directory that cannot be created (EACCES, EROFS, ENOTDIR), or the seed write fails (ENOSPC, read-only fs). Path is malformed or on an unavailable mount.

Common situations: The feature.mcp.memory_file path namespace resolves to a read-only or permission-restricted location; the path contains a segment that is a file (ENOTDIR); disk full at app startup; sandboxed process lacks write access to the configured userData dir; env path supplied by a launcher points at a missing/unwritable mount.

Related errors


AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12). Data as JSON: /api/errors/21e8029849b65d62. Report an issue: GitHub.

Appendix: source

Thrown at src/main/ai/mcp/servers/memory.ts:70

    await manager._ensureMemoryPathExists()
    await manager._loadGraphFromDisk()
    return manager
  }

  private async _ensureMemoryPathExists(): Promise<void> {
    try {
      const directory = path.dirname(this.memoryPath)
      await fs.mkdir(directory, { recursive: true })
      try {
        await fs.access(this.memoryPath)
      } catch (error) {
        // File doesn't exist, create an empty file with initial structure
        await fs.writeFile(this.memoryPath, JSON.stringify({ entities: [], relations: [] }, null, 2))
      }
    } catch (error) {
      logger.error('Failed to ensure memory path exists:', error as Error)
      // Propagate the error or handle it more gracefully depending on requirements
      throw new McpError(
        ErrorCode.InternalError,
        `Failed to ensure memory path: ${error instanceof Error ? error.message : String(error)}`
      )
    }
  }

  // Load graph from disk into memory (called once during initialization)
  private async _loadGraphFromDisk(): Promise<void> {
    try {
      const data = await fs.readFile(this.memoryPath, 'utf-8')
      // Handle empty file case
      if (data.trim() === '') {
        this.entities = new Map()
        this.relations = new Set()
        // Optionally write the initial empty structure back
        await this._persistGraph()
        return
      }

View on GitHub (pinned to 726446b54c)