puppetlabs/puppet · error · Puppet::Util::Windows::Error
Invalid DACL
Error message
Invalid DACL
What it means
Raised by parse_dacl when the DACL pointer returned by GetSecurityInfo for a filesystem object fails the Win32 IsValidAcl validation. That means the discretionary ACL read off the object is structurally invalid or the pointer is null (the code has a REMIND comment that a NULL DACL is not handled). It surfaces through get_security_descriptor when Puppet reads permissions for the group/owner/allow/deny properties.
Source
Thrown at lib/puppet/util/windows/security.rb:468
Puppet::Util::Windows::SID.string_to_sid_ptr(sid) do |sid_ptr|
if Puppet::Util::Windows::SID.IsValidSid(sid_ptr) == FFI::WIN32_FALSE
raise Puppet::Util::Windows::Error, _("Invalid SID")
end
if AddAccessDeniedAceEx(acl, ACL_REVISION, inherit, mask, sid_ptr) == FFI::WIN32_FALSE
raise Puppet::Util::Windows::Error, _("Failed to add access control entry")
end
end
# ensure this method is void if it doesn't raise
nil
end
def parse_dacl(dacl_ptr)
# REMIND: need to handle NULL DACL
if IsValidAcl(dacl_ptr) == FFI::WIN32_FALSE
raise Puppet::Util::Windows::Error, _("Invalid DACL")
end
dacl_struct = ACL.new(dacl_ptr)
ace_count = dacl_struct[:AceCount]
dacl = Puppet::Util::Windows::AccessControlList.new
# deny all
return dacl if ace_count == 0
0.upto(ace_count - 1) do |i|
FFI::MemoryPointer.new(:pointer, 1) do |ace_ptr|
next if GetAce(dacl_ptr, i, ace_ptr) == FFI::WIN32_FALSE
# ACE structures vary depending on the type. We are only concerned with
# ACCESS_ALLOWED_ACE and ACCESS_DENIED_ACEs, which have the same layout
ace = GENERIC_ACCESS_ACE.new(ace_ptr.get_pointer(0)) # deref LPVOID *
View on GitHub (pinned to e227c27540)
Solutions
- Check whether the object really has a DACL before parsing (a NULL DACL is legal and means 'grant everyone')
- Rebuild the object's security: copy data elsewhere, delete and recreate the file, or reset with icacls <path> /reset
- Exclude the affected path from Puppet management until its descriptor is repaired
- Inspect e.code from the error for the underlying Win32 failure reason
Defensive patterns
Strategy: try-catch
Try / catch
begin
sd = Puppet::Util::Windows::Security.get_security_descriptor(path)
rescue Puppet::Util::Windows::Error => e
raise unless e.message.include?('Invalid DACL')
raise Puppet::Error, "Security descriptor on #{path} is unreadable (NULL or corrupt DACL); run icacls '#{path}' /reset"
end Prevention
- Audit target trees with icacls before managing them to catch corrupt descriptors early
- Do not assume every object has a DACL; treat NULL DACL as 'everyone full control'
- Keep backups that include ACLs so a /reset loses nothing
When it happens
Trigger: get_security_descriptor (or Puppet's acl provider reading mode) on a file whose security descriptor is corrupted, on an object whose DACL is NULL (no DACL present, so IsValidAcl receives a null pointer), or on reparse points/special filesystem objects where the returned DACL structure is malformed.
Common situations: Corrupted NTFS metadata after disk issues; files created by non-Windows systems or unusual drivers; objects with a NULL DACL (everyone-full-access) that Puppet tries to manage; some clustered or ReFS layouts.
Related errors
- Failed to get security descriptor control
- Failed to initialize ACL
- Failed to set security information
- Failed to add access control entry
- Failed to open '%{path}'
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/b3f3a7dc2d63367e.
Report an issue: GitHub.