{"record":{"id":"8b6377f27163ee2e","repo":"juicedata/juicefs","slug":"invalid-default-acl-the-user-group-and-other-ent","errorCode":null,"errorMessage":"Invalid default ACL: the user, group and other entries are required.","messagePattern":"Invalid default ACL: the user, group and other entries are required\\.","errorType":"validation","errorClass":"AclException","httpStatus":null,"severity":"error","filePath":"sdk/java/src/main/java/io/juicefs/utils/AclTransformation.java","lineNumber":190,"sourceCode":"        throw new AclException(\"Invalid ACL: this entry type must not have a name: \" + entry + \".\");\n      }\n      prevEntry = entry;\n    }\n\n    ScopedAclEntries scopedEntries = new ScopedAclEntries(aclBuilder);\n    checkMaxEntries(scopedEntries);\n\n    // Search for the required base access entries.  If there is a default ACL,\n    // then do the same check on the default entries.\n    for (AclEntryType type : EnumSet.of(USER, GROUP, OTHER)) {\n      AclEntry accessEntryKey = new AclEntry.Builder().setScope(ACCESS).setType(type).build();\n      if (Collections.binarySearch(scopedEntries.getAccessEntries(), accessEntryKey, ACL_ENTRY_COMPARATOR) < 0) {\n        throw new AclException(\"Invalid ACL: the user, group and other entries are required.\");\n      }\n      if (!scopedEntries.getDefaultEntries().isEmpty()) {\n        AclEntry defaultEntryKey = new AclEntry.Builder().setScope(DEFAULT).setType(type).build();\n        if (Collections.binarySearch(scopedEntries.getDefaultEntries(), defaultEntryKey, ACL_ENTRY_COMPARATOR) < 0) {\n          throw new AclException(\"Invalid default ACL: the user, group and other entries are required.\");\n        }\n      }\n    }\n    return Collections.unmodifiableList(aclBuilder);\n  }\n\n  private static void checkMaxEntries(ScopedAclEntries scopedEntries) throws AclException {\n    List<AclEntry> accessEntries = scopedEntries.getAccessEntries();\n    List<AclEntry> defaultEntries = scopedEntries.getDefaultEntries();\n    if (accessEntries.size() > MAX_ENTRIES) {\n      throw new AclException(\"Invalid ACL: ACL has \" + accessEntries.size() + \" access entries, which exceeds maximum of \" + MAX_ENTRIES + \".\");\n    }\n    if (defaultEntries.size() > MAX_ENTRIES) {\n      throw new AclException(\"Invalid ACL: ACL has \" + defaultEntries.size() + \" default entries, which exceeds maximum of \" + MAX_ENTRIES + \".\");\n    }\n  }\n\n  private static void calculateMasks(List<AclEntry> aclBuilder, EnumMap<AclEntryScope, AclEntry> providedMask, EnumSet<AclEntryScope> maskDirty, EnumSet<AclEntryScope> scopeDirty) throws AclException {","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/sdk/java/src/main/java/io/juicefs/utils/AclTransformation.java#L172-L208","documentation":"The same invariant check as the access-ACL case, applied to the DEFAULT scope: if a default ACL exists at all (getDefaultEntries() is non-empty), it must contain DEFAULT user, group and other entries. This is only raised when a default ACL is present but incomplete, so it catches partially specified default ACLs.","triggerScenarios":"Calling mergeAclEntries/replaceAclEntries with a default ACL (e.g. 'default:user:alice:rwx' or 'default:group::r-x' alone) that lacks the required default:user::, default:group:: and default:other:: trio.","commonSituations":"Setting a default ACL for inheritance on a directory by adding only named default entries; copying a default ACL from another tool that omitted base entries; hand-editing an ACL dump and dropping default:other::.","solutions":["Include the full set of base default entries (default:user::, default:group::, default:other::) whenever any default entry is present.","If only an access ACL was intended, remove all default: entries from the spec instead of leaving a partial default ACL.","Compute the base default permissions from the existing access ACL and add them to the spec."],"exampleFix":"// before\nmergeAclEntries(path, \"default:user:alice:rwx\");\n// after\nmergeAclEntries(path, \"default:user::rwx,default:user:alice:rwx,default:group::r-x,default:other::r--\");","handlingStrategy":"validation","validationCode":"def default_acl_complete(entries):\n    d = [e for e in entries if e.getScope() == AclEntryScope.DEFAULT]\n    if not d:\n        return True\n    types = {e.getType() for e in d}\n    return {AclEntryType.USER, AclEntryType.GROUP, AclEntryType.OTHER} <= types","typeGuard":null,"tryCatchPattern":"try {\n  mergeAclEntries(path, spec);\n} catch (AclException e) {\n  if (e.getMessage().contains(\"Invalid default ACL\")) {\n    spec = addBaseDefaultEntries(spec);\n    mergeAclEntries(path, spec);\n  } else throw e;\n}","preventionTips":["Whenever any default: entry is present, emit the full default base trio too.","Derive default base permissions from the access ACL's base entries.","Test directory ACLs for the complete default trio before applying."],"tags":["acl","java","validation","default-acl"],"backgroundTag":"missing-required-argument","analyzedSha":"c9a67b23e8e08ec23ec331aa6f1675e2319e921c","analyzedAt":"2026-09-06T17:55:48.476Z","contentChangedAt":"2026-09-06T17:55:48.476Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}