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

  1. Check whether the object really has a DACL before parsing (a NULL DACL is legal and means 'grant everyone')
  2. Rebuild the object's security: copy data elsewhere, delete and recreate the file, or reset with icacls <path> /reset
  3. Exclude the affected path from Puppet management until its descriptor is repaired
  4. 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

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


AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21). Data as JSON: /api/errors/b3f3a7dc2d63367e. Report an issue: GitHub.