{"record":{"id":"5ea0ab30817faa5a","repo":"CherryHQ/cherry-studio","slug":"directory-not-found-validpath","errorCode":null,"errorMessage":"Directory not found: ${validPath}","messagePattern":"Directory not found: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"src/main/ai/mcp/servers/filesystem/tools/glob.ts","lineNumber":53,"sourceCode":"// Handler implementation\nexport async function handleGlobTool(args: unknown, baseDir: string) {\n  const parsed = GlobToolSchema.safeParse(args)\n  if (!parsed.success) {\n    throw new Error(`Invalid arguments for glob: ${parsed.error}`)\n  }\n\n  const searchPath = parsed.data.path || baseDir\n  const validPath = await validatePath(searchPath, baseDir)\n\n  // Verify the search directory exists\n  try {\n    const stats = await fs.stat(validPath)\n    if (!stats.isDirectory()) {\n      throw new Error(`Path is not a directory: ${validPath}`)\n    }\n  } catch (error: unknown) {\n    if (error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT') {\n      throw new Error(`Directory not found: ${validPath}`)\n    }\n    throw error\n  }\n\n  // Validate pattern\n  const pattern = parsed.data.pattern.trim()\n  if (!pattern) {\n    throw new Error('Pattern cannot be empty')\n  }\n\n  const files: FileInfo[] = []\n  let truncated = false\n\n  // Build ripgrep arguments for file listing using --glob=pattern format\n  const rgArgs: string[] = [\n    '--files',\n    '--follow',\n    '--hidden',","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/mcp/servers/filesystem/tools/glob.ts#L35-L71","documentation":"fs.stat on the glob search directory rejected with ENOENT — the validated path resolves inside the workspace root but does not exist on disk. Uses a type-narrowed catch (`'code' in error && error.code === 'ENOENT'`) rather than the `any`-cast pattern used elsewhere.","triggerScenarios":"The caller passed a path argument that points at a directory which has never existed or was removed; a typo in the directory name; the workspace root has not been created yet.","commonSituations":"A model guessing a directory layout that does not match the actual tree; a freshly initialized workspace where the feature directory has not been scaffolded.","solutions":["Omit the path argument to fall back to the base directory, which is guaranteed to exist (ensureBaseDir creates it in the constructor).","List the parent directory with ls to discover the correct subdirectory name.","If the workspace root itself is missing, confirm application.getPath('feature.mcp.workspace') returns a writable location."],"exampleFix":"// before\nif (error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT') {\n  throw new Error(`Directory not found: ${validPath}`)\n}\n\n// after — suggest the base directory fallback\nthrow new Error(`Directory not found: ${validPath}. Omit 'path' to search the base directory ${baseDir}.`)","handlingStrategy":"validation","validationCode":"// Confirm the search directory exists, or fall back to base.\nimport { stat } from 'fs/promises'\nasync function resolveSearchDir(p: string | undefined, baseDir: string): Promise<string> {\n  const dir = p ?? baseDir\n  try { await stat(dir) } catch { throw new Error(`Directory not found: ${dir}`) }\n  return dir\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Omit path to use the guaranteed-to-exist base directory.","List the parent directory to discover the correct subdirectory name.","Ensure the workspace root is created at server boot (ensureBaseDir).","Use absolute paths to avoid resolution ambiguity."],"tags":["filesystem","enoent","glob","mcp-tool"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}