apache/hadoop · error · InvalidAclOperationException

Default mask is required when a named default acl is present

Error message

Default mask is required when a named default acl is present.

What it means

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).

Source

Thrown at hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/services/AbfsAclHelper.java:125

        } else {
          accessAclTouched = true;
        }
      }
    }

    if (removeIndicationSet.contains(AbfsHttpConstants.ACCESS_MASK) && containsNamedAce(aclEntries, false)) {
      throw new InvalidAclOperationException("Access mask is required when a named access acl is present.");
    }

    if (accessAclTouched) {
      if (removeIndicationSet.contains(AbfsHttpConstants.ACCESS_MASK)) {
        aclEntries.remove(AbfsHttpConstants.ACCESS_MASK);
      }
      recalculateMask(aclEntries, false);
    }

    if (removeIndicationSet.contains(AbfsHttpConstants.DEFAULT_MASK) && containsNamedAce(aclEntries, true)) {
      throw new InvalidAclOperationException("Default mask is required when a named default acl is present.");
    }

    if (defaultAclTouched) {
      if (removeIndicationSet.contains(AbfsHttpConstants.DEFAULT_MASK)) {
        aclEntries.remove(AbfsHttpConstants.DEFAULT_MASK);
      }
      if (removeIndicationSet.contains(AbfsHttpConstants.DEFAULT_USER)) {
        aclEntries.put(AbfsHttpConstants.DEFAULT_USER, aclEntries.get(AbfsHttpConstants.ACCESS_USER));
      }
      if (removeIndicationSet.contains(AbfsHttpConstants.DEFAULT_GROUP)) {
        aclEntries.put(AbfsHttpConstants.DEFAULT_GROUP, aclEntries.get(AbfsHttpConstants.ACCESS_GROUP));
      }
      if (removeIndicationSet.contains(AbfsHttpConstants.DEFAULT_OTHER)) {
        aclEntries.put(AbfsHttpConstants.DEFAULT_OTHER, aclEntries.get(AbfsHttpConstants.ACCESS_OTHER));
      }
      recalculateMask(aclEntries, true);
    }
  }

View on GitHub (pinned to 2add963021)

Solutions

  1. 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
  2. Keep the mask: set 'default:mask:<perms>' to a value that covers the named entries instead of removing it
  3. Replace the entire ACL with fs.setAcl(path, fullSpec) containing a valid, complete default ACL including default:mask
  4. 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

Example fix

// before: removes the default mask while a named default ACE remains
// -> InvalidAclOperationException
fs.modifyAclEntries(path, Arrays.asList(
    AclEntry.parseAclEntry("default:mask:", true)));

// after: drop the named default entries together with the mask
fs.modifyAclEntries(path, Arrays.asList(
    AclEntry.parseAclEntry("default:user:alice:", true),
    AclEntry.parseAclEntry("default:mask:", true)));
Defensive patterns

Strategy: validation

Validate before calling

boolean keepsNamedDefault(AclStatus st) {
  return st.getEntries().stream().anyMatch(e ->
      e.getScope() == AclEntryScope.DEFAULT && e.getName() != null);
}

// before removing/emptying default:mask, ensure no named default ACE remains
if (removesDefaultMask(spec) && keepsNamedDefault(fs.getAclStatus(path))) {
  spec = stripDefaultMaskRemoval(spec); // or also remove the named default entries
}
fs.modifyAclEntries(path, spec);

Try / catch

try {
  fs.modifyAclEntries(path, spec);
} catch (InvalidAclOperationException e) {
  // spec would leave a named default entry without a default mask;
  // recompute the spec from getAclStatus and retry once
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/cbcc4b7ba2d972c7. Report an issue: GitHub.