{"record":{"id":"e8113b10d6cd28b1","repo":"CherryHQ/cherry-studio","slug":"file-not-found-filepath-e8113b","errorCode":null,"errorMessage":"File not found: ${filePath}","messagePattern":"File not found: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ai/mcp/servers/filesystem/tools/read.ts","lineNumber":48,"sourceCode":"// Handler implementation\nexport async function handleReadTool(args: unknown, baseDir: string) {\n  const parsed = ReadToolSchema.safeParse(args)\n  if (!parsed.success) {\n    throw new Error(`Invalid arguments for read: ${parsed.error}`)\n  }\n\n  const filePath = parsed.data.file_path\n  const validPath = await validatePath(filePath, baseDir)\n\n  // Check if file exists\n  try {\n    const stats = await fs.stat(validPath)\n    if (!stats.isFile()) {\n      throw new Error(`Path is not a file: ${filePath}`)\n    }\n  } catch (error: any) {\n    if (error.code === 'ENOENT') {\n      throw new Error(`File not found: ${filePath}`)\n    }\n    throw error\n  }\n\n  // Check if file is binary\n  if (await isBinaryFile(validPath)) {\n    throw new Error(`Cannot read binary file: ${filePath}`)\n  }\n\n  // Read file content\n  const content = await fs.readFile(validPath, 'utf-8')\n  const lines = content.split('\\n')\n\n  // Apply offset and limit\n  const offset = (parsed.data.offset || 1) - 1 // Convert to 0-based\n  const limit = parsed.data.limit || DEFAULT_READ_LIMIT\n\n  if (offset < 0 || offset >= lines.length) {","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/mcp/servers/filesystem/tools/read.ts#L30-L66","documentation":"Thrown by the read tool when fs.stat rejects with error.code === 'ENOENT'. validatePath already succeeded (the path is within the workspace root), but the file does not exist on disk. This is distinct from a workspace-access denial (error 327) and from the not-a-file case (error 320): validation passed, the inode is simply absent.","triggerScenarios":"Calling handleReadTool with a file_path inside the workspace root that has not been created, was deleted between validation and stat, or is misspelled. Also fires when realpath-style resolution in validatePath succeeds against a parent directory but the leaf file is missing.","commonSituations":"Reading a file before it is generated by a build step; typo in filename; race where the file is removed by another process between validatePath and fs.stat; relative path resolved against an unexpected baseDir.","solutions":["Verify the file exists (ls / fs.access) at the exact resolved path before calling read.","Check that any prerequisite build/generation step that produces the file has completed.","Confirm baseDir is the workspace root you expect, since relative paths resolve against it."],"exampleFix":"// before\nawait handleReadTool({ file_path: 'src/missing.ts' }, baseDir) // throws: File not found\n\n// after\nimport fs from 'fs/promises'\nawait fs.access(path.join(baseDir, 'src/index.ts')) // confirm first\nawait handleReadTool({ file_path: 'src/index.ts' }, baseDir)","handlingStrategy":"validation","validationCode":"import fs from 'fs/promises'\nasync function exists(p: string): Promise<boolean> {\n  try { await fs.access(p); return true } catch { return false }\n}\n// guard: if (!(await exists(resolved))) return","typeGuard":null,"tryCatchPattern":"try {\n  await handleReadTool(args, baseDir)\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('File not found')) {\n    // treat as missing-resource, skip or report\n  } else throw e\n}","preventionTips":["Cache file-existence at the source and refresh before each read if the workspace is volatile.","When paginating, stop when the prior read reports no more lines rather than guessing offsets.","Log the resolved absolute path on failure to spot typos and wrong baseDir quickly."],"tags":["filesystem","validation","mcp","read-tool","enoent"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}