java-native-access/jna · error · IllegalArgumentException
DACL is invalid
Error message
DACL is invalid
What it means
When setDACL is requested and a DACL is present, the library validates it with Advapi32.IsValidAcl. If the ACL structure fails Windows validation (bad AclRevision, size mismatch, corrupted ACEs), it throws IllegalArgumentException ('DACL is invalid').
Solutions
- Pre-check with Advapi32.INSTANCE.IsValidAcl(dacl.getPointer()) and rebuild the ACL if false.
- Rebuild the DACL with Advapi32Util.createAccessControlList or similar helper rather than hand-writing bytes.
- Re-extract the ACL from the source descriptor using the correct offsets (getSecurityDescriptorDacl).
- Skip the DACL component (setDACL=false) if invalid, then set it separately from a freshly built ACL.
Example fix
// before
Advapi32Util.setSecurityDescriptorComponents(sd, true, true, true, true, false, false);
// after
if (sd.getDiscretionaryACL() != null && Advapi32.INSTANCE.IsValidAcl(sd.getDiscretionaryACL().getPointer())) {
Advapi32Util.setSecurityDescriptorComponents(sd, true, true, true, true, false, false);
} Defensive patterns
Strategy: validation
Validate before calling
ACL dacl = securityDescriptor.getDiscretionaryACL();
if (dacl == null || !Advapi32.INSTANCE.IsValidAcl(dacl.getPointer())) {
throw new IllegalStateException("DACL missing or invalid");
} Type guard
boolean isValidDACL(SECURITY_DESCRIPTOR_RELATIVE sd) {
ACL a = sd.getDiscretionaryACL();
return a != null && Advapi32.INSTANCE.IsValidAcl(a.getPointer());
} Try / catch
try {
Advapi32Util.setSecurityDescriptorComponents(sd, false, false, true, false, false, false);
} catch (IllegalArgumentException e) {
log.error("DACL rejected: " + e.getMessage());
} Prevention
- Run Advapi32.INSTANCE.IsValidAcl on any ACL before applying it.
- Build ACLs with library helpers instead of hand-writing ACE bytes.
- Verify AclSize matches the actual buffer after manual construction.
When it happens
Trigger: setDACL=true where the ACL bytes are corrupted or inconsistent: declared AclSize not matching buffer, malformed ACEs, ACL built by hand with wrong header fields.
Common situations: Manually constructed ACL structures with incorrect ACE sizes; copying ACL memory between descriptors without fixing offsets; truncated descriptor buffers causing partial ACL reads.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- SACL is invalid
- Group PSID is invalid
- Owner PSID is invalid
- SECURITY_DESCRIPTOR_RELATIVE does not contain DACL
- SECURITY_DESCRIPTOR_RELATIVE does not contain group
AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12).
Data as JSON: /api/errors/fbb9ef441469bdc1.
Report an issue: GitHub.
Appendix: source
Thrown at contrib/platform/src/com/sun/jna/platform/win32/Advapi32Util.java:2893
throw new IllegalArgumentException("SECURITY_DESCRIPTOR_RELATIVE does not contain owner");
if (!Advapi32.INSTANCE.IsValidSid(psidOwner))
throw new IllegalArgumentException("Owner PSID is invalid");
infoType |= OWNER_SECURITY_INFORMATION;
}
if (setGroup) {
if (psidGroup == null)
throw new IllegalArgumentException("SECURITY_DESCRIPTOR_RELATIVE does not contain group");
if (!Advapi32.INSTANCE.IsValidSid(psidGroup))
throw new IllegalArgumentException("Group PSID is invalid");
infoType |= GROUP_SECURITY_INFORMATION;
}
if (setDACL) {
if (dacl == null)
throw new IllegalArgumentException("SECURITY_DESCRIPTOR_RELATIVE does not contain DACL");
if (!Advapi32.INSTANCE.IsValidAcl(dacl.getPointer()))
throw new IllegalArgumentException("DACL is invalid");
infoType |= DACL_SECURITY_INFORMATION;
}
if (setSACL) {
if (sacl == null)
throw new IllegalArgumentException("SECURITY_DESCRIPTOR_RELATIVE does not contain SACL");
if (!Advapi32.INSTANCE.IsValidAcl(sacl.getPointer()))
throw new IllegalArgumentException("SACL is invalid");
infoType |= SACL_SECURITY_INFORMATION;
}
/*
* Control bits SE_DACL_PROTECTED/SE_SACL_PROTECTED indicate the *ACL is protected. The *ACL_SECURITY_INFORMATION flags
* are meta flags for SetNamedSecurityInfo and are not stored in the SD. If either *ACLProtectedStatus is set,
* get the current status from the securityDescriptor and apply as such, otherwise the ACL remains at its default.
*/
if (setDACLProtectedStatus) {
if ((securityDescriptor.Control & SE_DACL_PROTECTED) != 0) {View on GitHub (pinned to d036ad9781)