CherryHQ/cherry-studio · error · Error

Required agent prompt file is not a regular file: ${matchedP

Error message

Required agent prompt file is not a regular file: ${matchedPath}

What it means

Sibling of error 89 but for the case-insensitive fallback: resolveFile found a directory entry whose lowercased name matches the requested name, yet lstat of that matched path shows it is not a regular file or is a symlink. In failOnError mode this escalates to a throw; otherwise the function returns undefined.

Source

Thrown at src/main/ai/agents/prompt.ts:38

    if (fileStat.isFile() && !fileStat.isSymbolicLink()) return exact
    if (fileStat.isSymbolicLink()) logger.warn('Ignoring symbolic link in agent prompt data', { path: exact })
    if (failOnError) throw new Error(`Required agent prompt file is not a regular file: ${exact}`)
    return undefined
  } catch (error) {
    if (failOnError && (error as NodeJS.ErrnoException).code !== 'ENOENT') throw error
    // exact match not found, try case-insensitive
  }

  try {
    const entries = await readdir(dir)
    const target = name.toLowerCase()
    const match = entries.find((e) => e.toLowerCase() === target)
    if (!match) return undefined
    const matchedPath = path.join(dir, match)
    const fileStat = await lstat(matchedPath)
    if (fileStat.isFile() && !fileStat.isSymbolicLink()) return matchedPath
    if (fileStat.isSymbolicLink()) logger.warn('Ignoring symbolic link in agent prompt data', { path: matchedPath })
    if (failOnError) throw new Error(`Required agent prompt file is not a regular file: ${matchedPath}`)
    return undefined
  } catch (error) {
    if (failOnError) throw error
    return undefined
  }
}

async function isRealDirectory(dir: string): Promise<boolean> {
  try {
    const directoryStat = await lstat(dir)
    if (directoryStat.isSymbolicLink()) {
      logger.warn('Ignoring symbolic-link directory in agent prompt data', { path: dir })
      return false
    }
    return directoryStat.isDirectory()
  } catch {
    return false
  }

View on GitHub (pinned to 726446b54c)

Solutions

  1. Inspect the matched path from the error: `ls -la <matchedPath>` and `readlink <matchedPath>`.
  2. Remove or replace the offending entry with a real regular file of the intended name.
  3. Use exact-case filenames for prompt resources so the case-insensitive fallback is not exercised.
  4. Avoid storing prompt data on filesystems that confuse symlinked and real entries.

Example fix

// before: case-insensitive match lands on a symlink
prompts/System.MD -> /elsewhere   (requested 'system.md')

// after: real file with correct case
rm prompts/System.MD
echo "..." > prompts/system.md
Defensive patterns

Strategy: validation

Validate before calling

import { lstat, readdir } from 'node:fs/promises'
import path from 'node:path'
async function findRealPromptFile(dir: string, name: string): Promise<string | undefined> {
  const exact = path.join(dir, name)
  try {
    const s = await lstat(exact)
    if (s.isFile() && !s.isSymbolicLink()) return exact
  } catch { /* fall through */ }
  const target = name.toLowerCase()
  const match = (await readdir(dir)).find((e) => e.toLowerCase() === target)
  if (!match) return undefined
  const s = await lstat(path.join(dir, match))
  return s.isFile() && !s.isSymbolicLink() ? path.join(dir, match) : undefined
}

Type guard

function isRegularFile(stat: import('node:fs').Stats): boolean {
  return stat.isFile() && !stat.isSymbolicLink()
}

Try / catch

try {
  const resolved = await resolveFile(dir, name, true)
} catch (e) {
  if (e instanceof Error && /not a regular file/.test(e.message)) {
    // case-insensitive match was a symlink/special file; abort
  } else throw e
}

Prevention

When it happens

Trigger: resolveFile(dir, name, failOnError=true) finds no exact match, enumerates the directory case-insensitively, finds a candidate, but that candidate is a symlink/dir/special file rather than a regular file.

Common situations: Case-insensitive filesystem collisions (macOS/Windows) where a symlink or directory name matches the requested file; symlinked prompt data on synced storage; tampering.

Related errors


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