{"record":{"id":"4e85afed4da3630a","repo":"CherryHQ/cherry-studio","slug":"failed-to-read-required-agent-prompt-file-filep","errorCode":null,"errorMessage":"Failed to read required agent prompt file: ${filePath}","messagePattern":"Failed to read required agent prompt file: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ai/agents/prompt.ts","lineNumber":272,"sourceCode":"  }\n\n  /**\n   * Read a file with mtime-based caching. Returns undefined if the file does not exist.\n   */\n  private async readCachedFile(filePath: string, expectedRoot: string, failOnError: true): Promise<string>\n  private async readCachedFile(\n    filePath: string,\n    expectedRoot?: string,\n    failOnError?: false\n  ): Promise<string | undefined>\n  private async readCachedFile(\n    filePath: string,\n    expectedRoot = path.dirname(filePath),\n    failOnError = false\n  ): Promise<string | undefined> {\n    const fail = (error: unknown): undefined => {\n      if (failOnError) {\n        throw new Error(`Failed to read required agent prompt file: ${filePath}`, { cause: error })\n      }\n      return undefined\n    }\n\n    let fileStat\n    try {\n      fileStat = await lstat(filePath)\n      if (!fileStat.isFile() || fileStat.isSymbolicLink()) {\n        logger.warn('Ignoring non-regular file in agent prompt data', { path: filePath })\n        return fail(new Error('Path is not a regular file'))\n      }\n    } catch (error) {\n      return fail(error)\n    }\n\n    try {\n      const [resolvedRoot, resolvedFile] = await Promise.all([realpath(expectedRoot), realpath(filePath)])\n      const relative = path.relative(resolvedRoot, resolvedFile)","sourceCodeStart":254,"sourceCodeEnd":290,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/agents/prompt.ts#L254-L290","documentation":"Thrown by PromptBuilder.readCachedFile (failOnError=true) as a wrapper around any underlying failure to read a required prompt file — the path is not a regular file, lstat throws (e.g. ENOENT, EACCES), or reading the file content fails. The original error is attached via Error cause so the real reason is preserved. This is the hard-fail path for prompt files the agent cannot run without.","triggerScenarios":"readCachedFile(filePath, expectedRoot, failOnError=true) is called and the file is missing, not readable, not a regular file, or the read itself throws.","commonSituations":"A required prompt file was deleted or never installed; file permissions deny the app read access; the path points at a directory or symlink; packaging omitted required prompt resources; ENOENT after a partial upgrade.","solutions":["Inspect error.cause for the real reason (ENOENT/EACCES/'not a regular file').","Confirm the file exists at the path and is a readable regular file: `ls -la <filePath>`.","Fix permissions or ownership so the app process can read it.","Reinstall/restore the prompt resource from packaging, or mark it optional by calling readCachedFile without failOnError."],"exampleFix":"// before: required prompt file missing or unreadable\nawait builder.readCachedFile('/app/prompts/required.md', root, true)\n\n// after: ensure the file ships and is readable, or treat as optional\nawait fs.promises.access(filePath, fs.constants.R_OK)\nawait builder.readCachedFile(filePath, root, true)","handlingStrategy":"try-catch","validationCode":"import { access, constants, lstat } from 'node:fs/promises'\nasync function canReadPromptFile(p: string): Promise<boolean> {\n  try {\n    await access(p, constants.R_OK)\n    const s = await lstat(p)\n    return s.isFile() && !s.isSymbolicLink()\n  } catch {\n    return false\n  }\n}\nif (!(await canReadPromptFile(filePath))) {\n  // skip or fail with a clearer message before calling readCachedFile(failOnError=true)\n}","typeGuard":"function isReadableRegularFile(stat: import('node:fs').Stats): boolean {\n  return stat.isFile() && !stat.isSymbolicLink()\n}","tryCatchPattern":"try {\n  const content = await builder.readCachedFile(filePath, root, true)\n} catch (e) {\n  if (e instanceof Error && /Failed to read required agent prompt file/.test(e.message)) {\n    // inspect e.cause for ENOENT/EACCES/'not a regular file'\n    logger.error('Required prompt file unreadable', { filePath, cause: (e as Error & { cause?: unknown }).cause })\n  } else throw e\n}","preventionTips":["Ship all required prompt resources in packaging.","Set file permissions so the app can read prompt files.","Use failOnError only for resources the agent cannot run without."],"tags":["filesystem","agents","prompts","io","cause"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}