apache/hadoop · error · InvalidAclOperationException

Cannot remove user, group or other entry from access ACL.

Error message

Cannot remove user, group or other entry from access ACL.

What it means

removeNamedAceAndUpdateSet in AbfsAclHelper fails fast when the removal spec targets the three mandatory access entries. A POSIX access ACL must always contain the base 'user', 'group' and 'other' entries, so removeAclEntries (and modify paths with removal semantics) throw InvalidAclOperationException('Cannot remove user, group or other entry from access ACL.') instead of producing an invalid ACL. Named entries (user:<name>, group:<name>) are legal removal targets.

Source

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

    for (Map.Entry<String, String> entry : aclEntries.entrySet()) {
      if (entry.getKey().contains(AbfsHttpConstants.AT)) {
        return true;
      }
    }
    return false;
  }

  private static boolean removeNamedAceAndUpdateSet(String entry, boolean isDefaultAcl, Set<String> removeIndicationSet,
                                                    Map<String, String> aclEntries)
      throws AzureBlobFileSystemException {
    final int startIndex = isDefaultAcl ? 1 : 0;
    final String[] entryParts = entry.split(AbfsHttpConstants.COLON);
    final String tag = isDefaultAcl ? AbfsHttpConstants.DEFAULT_SCOPE + entryParts[startIndex] + AbfsHttpConstants.COLON
        : entryParts[startIndex] + AbfsHttpConstants.COLON;

    if ((entry.equals(AbfsHttpConstants.ACCESS_USER) || entry.equals(AbfsHttpConstants.ACCESS_GROUP)
        || entry.equals(AbfsHttpConstants.ACCESS_OTHER))) {
      throw new InvalidAclOperationException("Cannot remove user, group or other entry from access ACL.");
    }

    boolean touched = false;
    if (!isNamedAce(entry)) {
      removeIndicationSet.add(tag); // this must not be a access user, group or other
      touched = true;
    } else {
      if (aclEntries.remove(entry) != null) {
        touched = true;
      }
    }
    return touched;
  }

  private static void recalculateMask(Map<String, String> aclEntries, boolean isDefaultMask) {
    FsAction mask = FsAction.NONE;
    if (!isExtendAcl(aclEntries, isDefaultMask)) {
      return;

View on GitHub (pinned to 2add963021)

Solutions

  1. Filter 'user', 'group' and 'other' out of the removal list before calling fs.removeAclEntries
  2. To change base-entry permissions, use fs.setPermission(path, FsPermission) instead of removing entries
  3. To clear all default entries, use fs.removeDefaultAcl(path) rather than removing entries individually
  4. Keep removeAclEntries for named entries only (user:<name>, group:<name>), which are always legal to remove

Example fix

// before: base entries passed to removal -> InvalidAclOperationException
List<AclEntry> spec = fs.getAclStatus(path).getEntries().stream()
    .map(AclEntry::toString)
    .map(s -> AclEntry.parseAclEntry(s + ":", true))
    .collect(Collectors.toList());
fs.removeAclEntries(path, spec);

// after: only named entries are removable
List<AclEntry> spec = fs.getAclStatus(path).getEntries().stream()
    .filter(e -> e.getName() != null) // skips user/group/other base entries
    .map(e -> AclEntry.parseAclEntry(e.toString() + ":", true))
    .collect(Collectors.toList());
fs.removeAclEntries(path, spec);
Defensive patterns

Strategy: validation

Validate before calling

List<AclEntry> removable = spec.stream()
    .filter(e -> e.getName() != null) // only named ACEs; skips user/group/other base entries
    .collect(Collectors.toList());
fs.removeAclEntries(path, removable);

Try / catch

try {
  fs.removeAclEntries(path, spec);
} catch (InvalidAclOperationException e) {
  // base entry removal attempted: switch to setPermission for user/group/other bits
}

Prevention

When it happens

Trigger: fs.removeAclEntries(path, spec) where an entry string equals 'user:', 'group:' or 'other:' (the base access entries). Typical bug: iterating over getAclStatus().getEntries() and passing every entry to removeAclEntries without filtering out the base ones.

Common situations: Porting 'setfacl -x u,g,o' style cleanup scripts; generic ACL-diff tooling that treats all entries as removable; misunderstanding that base-entry permissions are changed via setPermission, not by ACL removal.

Related errors


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