{"record":{"id":"9718ebb564a4ec4c","repo":"CherryHQ/cherry-studio","slug":"directory-not-empty-targetpath-use-recursive","errorCode":null,"errorMessage":"Directory not empty: ${targetPath}. Use recursive=true to delete non-empty directories.","messagePattern":"Directory not empty: (.+?)\\. Use recursive=true to delete non-empty directories\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"src/main/ai/mcp/servers/filesystem/tools/delete.ts","lineNumber":69,"sourceCode":"  const relativePath = path.relative(baseDir, validPath)\n\n  // Perform deletion\n  try {\n    if (isDirectory) {\n      if (recursive) {\n        // Delete directory recursively\n        await fs.rm(validPath, { recursive: true, force: true })\n      } else {\n        // Try to delete empty directory\n        await fs.rmdir(validPath)\n      }\n    } else {\n      // Delete file\n      await fs.unlink(validPath)\n    }\n  } catch (error: any) {\n    if (error.code === 'ENOTEMPTY') {\n      throw new Error(`Directory not empty: ${targetPath}. Use recursive=true to delete non-empty directories.`)\n    }\n    throw new Error(`Failed to delete: ${error.message}`)\n  }\n\n  // Log the operation\n  logger.info('Path deleted', {\n    path: validPath,\n    type: isDirectory ? 'directory' : 'file',\n    recursive: isDirectory ? recursive : undefined\n  })\n\n  // Format output\n  const itemType = isDirectory ? 'Directory' : 'File'\n  const recursiveNote = isDirectory && recursive ? ' (recursive)' : ''\n\n  return {\n    content: [\n      {","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/mcp/servers/filesystem/tools/delete.ts#L51-L87","documentation":"fs.rmdir on a non-empty directory rejected with code ENOTEMPTY because the caller set recursive=false (or omitted it, defaulting to false) but the target directory still contains entries. The message tells the caller to pass recursive=true. Caught by the server-level handler and returned as an isError tool result.","triggerScenarios":"Calling delete on a directory that contains files or subdirectories without setting recursive:true. The handler first fs.stat'd the target as a directory, then chose fs.rmdir over fs.rm because the recursive flag was false.","commonSituations":"A model assuming delete is recursive by default; an empty-looking directory that still holds hidden files (e.g. .DS_Store) or a .git folder; a directory the user expected to be empty but contains nested output.","solutions":["Re-invoke delete with recursive:true if intentional whole-tree removal is desired.","If only an empty directory should be removed, first list it (ls tool) and confirm it has no entries, including hidden ones.","Audit for hidden files like .DS_Store, .gitkeep, or editor temp files that make an 'empty' directory non-empty."],"exampleFix":"// before\nthrow new Error(`Directory not empty: ${targetPath}. Use recursive=true to delete non-empty directories.`)\n\n// after — include the entry count so the caller knows the scale\nconst entries = await fs.readdir(validPath)\nthrow new Error(`Directory not empty: ${targetPath} has ${entries.length} entries. Use recursive=true to delete.`)","handlingStrategy":"validation","validationCode":"// Detect a non-empty directory before calling delete without recursive.\nimport { readdir } from 'fs/promises'\nasync function isDirEmpty(p: string): Promise<boolean> {\n  const entries = await readdir(p)\n  return entries.length === 0\n}\nif (stats.isDirectory() && !recursive) {\n  const empty = await isDirEmpty(validPath)\n  if (!empty) throw new Error('Pass recursive=true to delete non-empty directory')\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pass recursive:true whenever deleting a directory that may contain entries.","Remember hidden files (.DS_Store, .gitkeep) make a directory non-empty.","List the directory first if you need to guard against accidental bulk deletion.","Treat ENOTEMPTY as a recoverable prompt for confirmation, not a hard failure."],"tags":["filesystem","enotempty","delete","mcp-tool"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}