{"record":{"id":"4a8a39e6a62500c7","repo":"apache/hadoop","slug":"iip-getpath-is-non-empty","errorCode":null,"errorMessage":"iip.getPath() + \" is non empty\"","messagePattern":"iip\\.getPath\\(\\) \\+ \" is non empty\"","errorType":"exception","errorClass":"PathIsNotEmptyDirectoryException","httpStatus":null,"severity":"error","filePath":"hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSDirDeleteOp.java","lineNumber":111,"sourceCode":"   * @throws IOException\n   */\n  static BlocksMapUpdateInfo delete(\n      FSNamesystem fsn, FSPermissionChecker pc, String src, boolean recursive,\n      boolean logRetryCache) throws IOException {\n    FSDirectory fsd = fsn.getFSDirectory();\n\n    if (FSDirectory.isExactReservedName(src)) {\n      throw new InvalidPathException(src);\n    }\n\n    final INodesInPath iip = fsd.resolvePath(pc, src, DirOp.WRITE_LINK);\n    if (fsd.isPermissionEnabled()) {\n      fsd.checkPermission(pc, iip, false, null, FsAction.WRITE, null,\n                          FsAction.ALL, true);\n    }\n    if (fsd.isNonEmptyDirectory(iip)) {\n      if (!recursive) {\n        throw new PathIsNotEmptyDirectoryException(\n            iip.getPath() + \" is non empty\");\n      }\n      DFSUtil.checkProtectedDescendants(fsd, iip);\n    }\n\n    return deleteInternal(fsn, iip, logRetryCache);\n  }\n\n  /**\n   * Delete a path from the name space\n   * Update the count at each ancestor directory with quota\n   * <br>\n   * Note: This is to be used by\n   * {@link org.apache.hadoop.hdfs.server.namenode.FSEditLog} only.\n   * <br>\n   *\n   * @param fsd the FSDirectory instance\n   * @param iip inodes of a path to be deleted","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSDirDeleteOp.java#L93-L129","documentation":"FSDirDeleteOp.delete checks isNonEmptyDirectory(iip) and, when the delete is non-recursive (recursive=false from FileSystem.delete(path, false) or 'hdfs dfs -rm' without -r), throws PathIsNotEmptyDirectoryException. HDFS deliberately refuses to silently discard a populated directory: a non-recursive delete only removes empty directories and files named exactly by the path. If recursive=true is passed, the same directory deletes fine (after a protected-descendants check).","triggerScenarios":"fs.delete(dirPath, false) where dirPath contains children; 'hdfs dfs -rm /some/dir' (without -r or -R) on a populated directory.","commonSituations":"Code ported from java.io.File.delete() or POSIX unlink() semantics where an explicit non-recursive delete is used as a safety guard; cleanup scripts that expect dirs to already be empty; tooling that intends 'delete only if empty' but does not handle the exception.","solutions":["If the intent is to remove everything, pass recursive=true: fs.delete(dir, true).","If the intent is 'delete only when empty', keep recursive=false and catch PathIsNotEmptyDirectoryException as the expected signal (via RemoteException.unwrap / checking the exception class name).","Alternatively list the directory first and decide: fs.listStatus(dir).length == 0 before deleting non-recursively."],"exampleFix":"// before\nfs.delete(dir, false); // throws if dir has children\n\n// after\nboolean removed;\nif (fs.getFileStatus(dir).isDirectory() && fs.listStatus(dir).length > 0) {\n  removed = fs.delete(dir, true);  // deliberate recursive delete\n} else {\n  removed = fs.delete(dir, false);\n}","handlingStrategy":"validation","validationCode":"boolean empty = fs.getFileStatus(dir).isDirectory()\n    ? fs.listStatus(dir).length == 0 : true;\nboolean removed = fs.delete(dir, /*recursive=*/ !empty);","typeGuard":null,"tryCatchPattern":"try {\n  fs.delete(dir, false);\n} catch (PathIsNotEmptyDirectoryException e) {\n  // only thrown client-side as RemoteException; unwrap first:\n  // IOException ioe = RemoteExceptionHandler.decode(...)  (catch IOException, check className)\n  // deliberate: directory was populated between check and delete\n  fs.delete(dir, true);\n}","preventionTips":["Decide recursion policy explicitly per call site; do not copy fs.delete(dir, false) from local-FS habits.","For 'delete only if empty' semantics, check listStatus(...).length == 0 first and treat the exception as expected.","In shell scripts, use hdfs dfs -rm -r for intentional recursive deletes; plain -rm fails on populated dirs."],"tags":["hdfs","delete","directory-not-empty","precondition"],"backgroundTag":"directory-not-empty","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}