CherryHQ/cherry-studio · error · Error

Failed to read journal at

Error message

Failed to read journal at ${journalPath}: ${(err as Error).message}

What it means

In memorySearch(), any error from opening or reading the journal that is NOT ENOENT is re-thrown wrapped with context. ENOENT is treated as 'no journal yet' and returns a friendly message; all other failures (EACCES, EIO, ENOSPC, etc.) bubble up as this wrapped Error, which the outer CallToolRequest catch converts into an isError response.

Solutions

  1. Check permissions on the journal file and parent directory: ls -la <agentDataPath>/memory/.
  2. Ensure the Electron process has read access (same user that wrote it).
  3. If the disk is failing, run filesystem checks and restore from backup.

Example fix

# before: file owned by root after a bad migration
ls -la memory/JOURNAL.jsonl  # -rw------- root root

# after: fix ownership to the app user
chown $USER:$USER memory/JOURNAL.jsonl
Defensive patterns

Strategy: try-catch

Validate before calling

import { access } from 'node:fs/promises'
import { constants } from 'node:fs'

async function isReadable(p: string): Promise<boolean> {
  try {
    await access(p, constants.R_OK)
    return true
  } catch {
    return false
  }
}

Try / catch

try {
  return await memorySearch(args)
} catch (err) {
  if (err instanceof Error && err.message.startsWith('Failed to read journal')) {
    logger.warn('Journal read failed', { error: err.message })
    return { content: [{ type: 'text', text: 'Journal temporarily unavailable.' }] }
  }
  throw err
}

Prevention

When it happens

Trigger: The journal exists but cannot be read: permission denied (EACCES), disk I/O error (EIO), path too long, or the file is locked by another process in a way that blocks the read.

Common situations: File permissions were changed after creation (chmod); the disk has bad sectors; antivirus or another process holds an exclusive lock; the userData directory was moved to read-only media.

Related errors


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

Appendix: source

Thrown at src/main/ai/mcp/servers/agentMemory.ts:298

    const memoryDir = await this.assertMemoryDirectory()
    const journalPath = await resolveFileCI(memoryDir, 'JOURNAL.jsonl')

    let fileContent: string
    try {
      const handle = await open(journalPath, withNoFollow(constants.O_RDONLY))
      try {
        const fileStat = await handle.stat()
        if (!fileStat.isFile()) throw new Error(`Agent journal must be a regular file: ${journalPath}`)
        fileContent = await handle.readFile('utf-8')
      } finally {
        await handle.close()
      }
    } catch (err) {
      if ((err as NodeJS.ErrnoException).code === 'ENOENT') {
        return { content: [{ type: 'text' as const, text: 'No journal entries found.' }] }
      }
      throw new Error(`Failed to read journal at ${journalPath}: ${(err as Error).message}`)
    }

    const queryLower = query.toLowerCase()
    const tagLower = tagFilter.toLowerCase()
    const matches: JournalEntry[] = []

    for (const line of fileContent.split('\n')) {
      if (!line.trim()) continue
      let entry: JournalEntry
      try {
        entry = JSON.parse(line)
      } catch {
        logger.warn('Skipping corrupted journal line', { journalPath, line: line.substring(0, 100) })
        continue
      }
      if (tagFilter && !entry.tags?.some((t) => t.toLowerCase() === tagLower)) continue
      if (query && !entry.text.toLowerCase().includes(queryLower)) continue
      matches.push(entry)

View on GitHub (pinned to 726446b54c)