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
- Inspect the matched path from the error: `ls -la <matchedPath>` and `readlink <matchedPath>`.
- Remove or replace the offending entry with a real regular file of the intended name.
- Use exact-case filenames for prompt resources so the case-insensitive fallback is not exercised.
- 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
- Use exact-case prompt filenames to avoid the case-insensitive fallback.
- Never symlink prompt resources.
- Avoid case-insensitive filesystems for prompt data when possible.
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
- Required agent prompt file is not a regular file: ${exact}
- Agent data file must be a real file: ${filePath}
- Agent data directory must be a real directory: ${agentDataPa
- Agent memory directory must be a real directory: ${memoryPat
- Refusing to recursively remove unsafe agent data path: ${age
AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12).
Data as JSON: /api/errors/272a8dc867491b64.
Report an issue: GitHub.