{"record":{"id":"cbcc4b7ba2d972c7","repo":"apache/hadoop","slug":"default-mask-is-required-when-a-named-default-acl","errorCode":null,"errorMessage":"Default mask is required when a named default acl is present.","messagePattern":"Default mask is required when a named default acl is present\\.","errorType":"validation","errorClass":"InvalidAclOperationException","httpStatus":null,"severity":"error","filePath":"hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/services/AbfsAclHelper.java","lineNumber":125,"sourceCode":"        } else {\n          accessAclTouched = true;\n        }\n      }\n    }\n\n    if (removeIndicationSet.contains(AbfsHttpConstants.ACCESS_MASK) && containsNamedAce(aclEntries, false)) {\n      throw new InvalidAclOperationException(\"Access mask is required when a named access acl is present.\");\n    }\n\n    if (accessAclTouched) {\n      if (removeIndicationSet.contains(AbfsHttpConstants.ACCESS_MASK)) {\n        aclEntries.remove(AbfsHttpConstants.ACCESS_MASK);\n      }\n      recalculateMask(aclEntries, false);\n    }\n\n    if (removeIndicationSet.contains(AbfsHttpConstants.DEFAULT_MASK) && containsNamedAce(aclEntries, true)) {\n      throw new InvalidAclOperationException(\"Default mask is required when a named default acl is present.\");\n    }\n\n    if (defaultAclTouched) {\n      if (removeIndicationSet.contains(AbfsHttpConstants.DEFAULT_MASK)) {\n        aclEntries.remove(AbfsHttpConstants.DEFAULT_MASK);\n      }\n      if (removeIndicationSet.contains(AbfsHttpConstants.DEFAULT_USER)) {\n        aclEntries.put(AbfsHttpConstants.DEFAULT_USER, aclEntries.get(AbfsHttpConstants.ACCESS_USER));\n      }\n      if (removeIndicationSet.contains(AbfsHttpConstants.DEFAULT_GROUP)) {\n        aclEntries.put(AbfsHttpConstants.DEFAULT_GROUP, aclEntries.get(AbfsHttpConstants.ACCESS_GROUP));\n      }\n      if (removeIndicationSet.contains(AbfsHttpConstants.DEFAULT_OTHER)) {\n        aclEntries.put(AbfsHttpConstants.DEFAULT_OTHER, aclEntries.get(AbfsHttpConstants.ACCESS_OTHER));\n      }\n      recalculateMask(aclEntries, true);\n    }\n  }","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/services/AbfsAclHelper.java#L107-L143","documentation":"Thrown by AbfsAclHelper (the engine behind AzureBlobFileSystem.modifyAclEntries) when an ACL modification would leave one or more named default entries (default:user:<name>:..., default:group:<name>:...) without a default mask. POSIX ACL rules require a mask whenever named entries exist, so the helper rejects any spec whose effect is to remove 'default:mask' while containsNamedAce(aclEntries, true) is still true. It surfaces as InvalidAclOperationException, a subclass of AzureBlobFileSystemException (and therefore IOException).","triggerScenarios":"Calling fs.modifyAclEntries(path, aclSpec) with a spec that removes/empties the default mask (e.g. 'default:mask:') while the path still has named default ACEs such as default:user:alice:rwx or default:group:devs:r-x. Internally: removeIndicationSet contains DEFAULT_MASK and containsNamedAce(aclEntries, true) returns true.","commonSituations":"Porting setfacl cleanup scripts from Linux to ABFS; stripping default masks after deleting most named default entries but leaving one behind; ACL specs copied from local filesystems that assume the mask is silently recalculated; HNS-enabled ADLS Gen2 accounts where modifyAclEntries is reachable.","solutions":["Remove the remaining named default entries (default:user:<name>, default:group:<name>) in the same modifyAclEntries call so no named default ACE survives without a mask","Keep the mask: set 'default:mask:<perms>' to a value that covers the named entries instead of removing it","Replace the entire ACL with fs.setAcl(path, fullSpec) containing a valid, complete default ACL including default:mask","Read the live ACL first with fs.getAclStatus(path) and compute the resulting spec so the invariant 'named default entries imply default:mask' holds before submitting"],"exampleFix":"// before: removes the default mask while a named default ACE remains\n// -> InvalidAclOperationException\nfs.modifyAclEntries(path, Arrays.asList(\n    AclEntry.parseAclEntry(\"default:mask:\", true)));\n\n// after: drop the named default entries together with the mask\nfs.modifyAclEntries(path, Arrays.asList(\n    AclEntry.parseAclEntry(\"default:user:alice:\", true),\n    AclEntry.parseAclEntry(\"default:mask:\", true)));","handlingStrategy":"validation","validationCode":"boolean keepsNamedDefault(AclStatus st) {\n  return st.getEntries().stream().anyMatch(e ->\n      e.getScope() == AclEntryScope.DEFAULT && e.getName() != null);\n}\n\n// before removing/emptying default:mask, ensure no named default ACE remains\nif (removesDefaultMask(spec) && keepsNamedDefault(fs.getAclStatus(path))) {\n  spec = stripDefaultMaskRemoval(spec); // or also remove the named default entries\n}\nfs.modifyAclEntries(path, spec);","typeGuard":null,"tryCatchPattern":"try {\n  fs.modifyAclEntries(path, spec);\n} catch (InvalidAclOperationException e) {\n  // spec would leave a named default entry without a default mask;\n  // recompute the spec from getAclStatus and retry once\n}","preventionTips":["Always read the live ACL with getAclStatus before remove/modify operations","Never remove default:mask while named default user/group entries exist","Prefer setAcl with a fully computed, valid spec when restructuring ACLs"],"tags":["azure","abfs","acl","posix-acl","hadoop","validation"],"backgroundTag":"acl-validation-failed","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}