{"record":{"id":"8889c1907bb98784","repo":"apache/hadoop","slug":"cannot-remove-user-group-or-other-entry-from-acce","errorCode":null,"errorMessage":"Cannot remove user, group or other entry from access ACL.","messagePattern":"Cannot remove user, group or other entry from access ACL\\.","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":208,"sourceCode":"    for (Map.Entry<String, String> entry : aclEntries.entrySet()) {\n      if (entry.getKey().contains(AbfsHttpConstants.AT)) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  private static boolean removeNamedAceAndUpdateSet(String entry, boolean isDefaultAcl, Set<String> removeIndicationSet,\n                                                    Map<String, String> aclEntries)\n      throws AzureBlobFileSystemException {\n    final int startIndex = isDefaultAcl ? 1 : 0;\n    final String[] entryParts = entry.split(AbfsHttpConstants.COLON);\n    final String tag = isDefaultAcl ? AbfsHttpConstants.DEFAULT_SCOPE + entryParts[startIndex] + AbfsHttpConstants.COLON\n        : entryParts[startIndex] + AbfsHttpConstants.COLON;\n\n    if ((entry.equals(AbfsHttpConstants.ACCESS_USER) || entry.equals(AbfsHttpConstants.ACCESS_GROUP)\n        || entry.equals(AbfsHttpConstants.ACCESS_OTHER))) {\n      throw new InvalidAclOperationException(\"Cannot remove user, group or other entry from access ACL.\");\n    }\n\n    boolean touched = false;\n    if (!isNamedAce(entry)) {\n      removeIndicationSet.add(tag); // this must not be a access user, group or other\n      touched = true;\n    } else {\n      if (aclEntries.remove(entry) != null) {\n        touched = true;\n      }\n    }\n    return touched;\n  }\n\n  private static void recalculateMask(Map<String, String> aclEntries, boolean isDefaultMask) {\n    FsAction mask = FsAction.NONE;\n    if (!isExtendAcl(aclEntries, isDefaultMask)) {\n      return;","sourceCodeStart":190,"sourceCodeEnd":226,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/services/AbfsAclHelper.java#L190-L226","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Filter 'user', 'group' and 'other' out of the removal list before calling fs.removeAclEntries","To change base-entry permissions, use fs.setPermission(path, FsPermission) instead of removing entries","To clear all default entries, use fs.removeDefaultAcl(path) rather than removing entries individually","Keep removeAclEntries for named entries only (user:<name>, group:<name>), which are always legal to remove"],"exampleFix":"// before: base entries passed to removal -> InvalidAclOperationException\nList<AclEntry> spec = fs.getAclStatus(path).getEntries().stream()\n    .map(AclEntry::toString)\n    .map(s -> AclEntry.parseAclEntry(s + \":\", true))\n    .collect(Collectors.toList());\nfs.removeAclEntries(path, spec);\n\n// after: only named entries are removable\nList<AclEntry> spec = fs.getAclStatus(path).getEntries().stream()\n    .filter(e -> e.getName() != null) // skips user/group/other base entries\n    .map(e -> AclEntry.parseAclEntry(e.toString() + \":\", true))\n    .collect(Collectors.toList());\nfs.removeAclEntries(path, spec);","handlingStrategy":"validation","validationCode":"List<AclEntry> removable = spec.stream()\n    .filter(e -> e.getName() != null) // only named ACEs; skips user/group/other base entries\n    .collect(Collectors.toList());\nfs.removeAclEntries(path, removable);","typeGuard":null,"tryCatchPattern":"try {\n  fs.removeAclEntries(path, spec);\n} catch (InvalidAclOperationException e) {\n  // base entry removal attempted: switch to setPermission for user/group/other bits\n}","preventionTips":["Treat user/group/other as immutable entries: change them with setPermission, never remove them","Filter getAclStatus() entries by getName() != null before building removal specs","Use removeDefaultAcl for whole-default-ACL cleanup instead of per-entry removal"],"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-22T20:17:22.307Z"}