{"record":{"id":"630eb2acb7c64f95","repo":"apache/hadoop","slug":"cannot-delete-rename-non-empty-protected-subdirect","errorCode":null,"errorMessage":"Cannot delete/rename non-empty protected subdirectory {}","messagePattern":"Cannot delete/rename non-empty protected subdirectory (.+?)","errorType":"exception","errorClass":"AccessControlException","httpStatus":null,"severity":"error","filePath":"hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/DFSUtil.java","lineNumber":1909,"sourceCode":"    }\n\n    String src = iip.getPath();\n    // Is src protected? Caller has already checked it is non-empty.\n    if (protectedDirs.contains(src)) {\n      throw new AccessControlException(\n          \"Cannot delete/rename non-empty protected directory \" + src);\n    }\n\n    // Are any descendants of src protected?\n    // The subSet call returns only the descendants of src since\n    // {@link Path#SEPARATOR} is \"/\" and '0' is the next ASCII\n    // character after '/'.\n    for (String descendant :\n        protectedDirs.subSet(src + Path.SEPARATOR, src + \"0\")) {\n      INodesInPath subdirIIP =\n          fsd.getINodesInPath(descendant, FSDirectory.DirOp.WRITE);\n      if (fsd.isNonEmptyDirectory(subdirIIP)) {\n        throw new AccessControlException(\n            \"Cannot delete/rename non-empty protected subdirectory \"\n            + descendant);\n      }\n    }\n\n    if (fsd.isProtectedSubDirectoriesEnable()) {\n      while (!src.isEmpty()) {\n        int index = src.lastIndexOf(Path.SEPARATOR_CHAR);\n        src = src.substring(0, index);\n        if (protectedDirs.contains(src)) {\n          throw new AccessControlException(\n              \"Cannot delete/rename subdirectory under protected subdirectory \"\n              + src);\n        }\n      }\n    }\n  }\n","sourceCodeStart":1891,"sourceCodeEnd":1927,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/DFSUtil.java#L1891-L1927","documentation":"Companion check to the protected-directory rule: DFSUtil.checkProtectedDescendants walks the protected set for descendants of the path being deleted (protectedDirs.subSet(src + '/', src + '0')). If any protected descendant is a non-empty directory, the delete/rename of its ancestor is refused with AccessControlException naming the descendant.","triggerScenarios":"Recursively deleting or renaming a parent directory when some deeper subdirectory is listed in fs.protected.directories and is non-empty, e.g. rm -r /data while /data/warehouse is protected.","commonSituations":"Broad cleanup jobs (rm -r /data) colliding with fine-grained protected paths configured underneath; protected zones nested inside temp trees.","solutions":["Delete the siblings individually and skip the protected subtree (delete contents of the protected descendant separately or leave it)","Empty the protected descendant so the non-empty condition no longer holds","Have the admin drop that descendant from fs.protected.directories if the operation is truly intended"],"exampleFix":"// before\nhdfs dfs -rm -r /data               // /data/warehouse protected and non-empty -> error\n// after: delete around the protected subtree\nhdfs dfs -rm /data/tmp/*\nhdfs dfs -rm /data/raw/*            // leave /data/warehouse in place","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  fs.delete(parentPath, true);\n} catch (AccessControlException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"protected subdirectory\")) {\n    // a protected descendant under parentPath is non-empty: fall back to\n    // listing children and deleting each non-protected one individually\n  } else {\n    throw e;\n  }\n}","preventionTips":["Before rm -r of large trees, cross-check the tree against the published protected-directories list","Implement recursive delete as per-child operations so one protected subtree does not abort the whole cleanup"],"tags":["hdfs","namenode","protected-directories","delete","rename","permissions"],"backgroundTag":"operation-blocked-by-policy","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}