{"record":{"id":"16f20b1d55988734","repo":"apache/hadoop","slug":"cannot-delete-rename-subdirectory-under-protected","errorCode":null,"errorMessage":"Cannot delete/rename subdirectory under protected subdirectory {}","messagePattern":"Cannot delete/rename subdirectory under 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":1920,"sourceCode":"    // {@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\n  /**\n   * Generates HdfsFileStatus flags.\n   * @param isEncrypted Sets HAS_CRYPT\n   * @param isErasureCoded Sets HAS_EC\n   * @param isSnapShottable Sets SNAPSHOT_ENABLED\n   * @param hasAcl Sets HAS_ACL\n   * @return HdfsFileStatus Flags\n   */\n  public static EnumSet<HdfsFileStatus.Flags> getFlags(\n      final boolean isEncrypted, final boolean isErasureCoded,\n      boolean isSnapShottable, boolean hasAcl) {","sourceCodeStart":1902,"sourceCodeEnd":1938,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/DFSUtil.java#L1902-L1938","documentation":"When dfs.protected.subdirectories.enable=true (DFSConfigKeys.DFS_PROTECTED_SUBDIRECTORIES_ENABLE), DFSUtil.checkProtectedDescendants additionally walks upward from the target path, stripping one component at a time, and refuses the delete/rename if ANY ancestor is a protected directory. This protects everything below a protected path, not just the protected directory itself.","triggerScenarios":"NameNode configured with dfs.protected.subdirectories.enable=true plus fs.protected.directories containing an ancestor; any delete or rename under that subtree (even of a single deep file) throws AccessControlException naming the protected ancestor.","commonSituations":"Admins tighten protection of whole subtrees; existing cleanup jobs that delete files below the protected directory start failing; the flag being enabled only on some NameNodes causing inconsistent behavior.","solutions":["Move workloads/data out of the protected subtree and stop deleting beneath it","Ask the admin to trim the ancestor from fs.protected.directories or set dfs.protected.subdirectories.enable=false, then restart/reload the NameNode","Restructure so scratch data no longer lives below protected directories"],"exampleFix":"// before (hdfs-site.xml on NameNode)\n<property><name>fs.protected.directories</name><value>/data</value></property>\n<property><name>dfs.protected.subdirectories.enable</name><value>true</value></property>\n// after (policy decision by admin: no subtree-wide protection)\n<property><name>dfs.protected.subdirectories.enable</name><value>false</value></property>","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  fs.delete(deepPath, false);\n} catch (AccessControlException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"under protected subdirectory\")) {\n    // an ancestor of deepPath is protected with dfs.protected.subdirectories.enable=true:\n    // relocate the data instead of deleting beneath the protected root\n  } else {\n    throw e;\n  }\n}","preventionTips":["Know whether dfs.protected.subdirectories.enable is on before scheduling deletes under protected roots","Keep scratch/temp data out of protected subtrees so subtree protection never surprises cleanup jobs","Admins: communicate that enabling the flag protects ALL descendants, not just the listed directory"],"tags":["hdfs","namenode","protected-directories","delete","rename","permissions","policy"],"backgroundTag":"operation-blocked-by-policy","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}