puppetlabs/puppet · error · Puppet::Util::Windows::Error

GetFileAttributes(#{file_name})

Error message

GetFileAttributes(#{file_name})

What it means

Puppet::Util::Windows::File.get_attributes queries GetFileAttributesW and raises Puppet::Util::Windows::Error when the API returns INVALID_FILE_ATTRIBUTES (0xFFFFFFFF). That sentinel means the path could not be queried - typically nonexistent path or access denied on some parent - so e.code is the discriminator. The method has an escape hatch: pass raise_on_invalid=false to get the raw sentinel back instead of an exception.

Source

Thrown at lib/puppet/util/windows/file.rb:93

      reparse_point = (result & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT
      if reparse_point && symlink_reparse_point?(path)
        # walk the symlink and try again...
        seen_paths << path.downcase
        path = readlink(path)
      else
        # file was found and its not a symlink
        return true
      end
    end

    false
  end
  module_function :exist?

  def get_attributes(file_name, raise_on_invalid = true)
    result = GetFileAttributesW(wide_string(file_name.to_s))
    if raise_on_invalid && result == INVALID_FILE_ATTRIBUTES
      raise Puppet::Util::Windows::Error, "GetFileAttributes(#{file_name})"
    end

    result
  end
  module_function :get_attributes

  def add_attributes(path, flags)
    oldattrs = get_attributes(path)

    if (oldattrs | flags) != oldattrs
      set_attributes(path, oldattrs | flags)
    end
  end
  module_function :add_attributes

  def remove_attributes(path, flags)
    oldattrs = get_attributes(path)

View on GitHub (pinned to e227c27540)

Solutions

  1. Verify the path spelling/existence first (File.exist?) when a miss is expected
  2. Pass raise_on_invalid: false and compare the result to INVALID_FILE_ATTRIBUTES yourself
  3. Inspect e.code: 5 means access denied (fix ACLs/elevation), 2/3 means missing (fix the path)
  4. For repeated probes on protected trees, run elevated or relax the parent-folder ACL

Example fix

// before
attrs = Puppet::Util::Windows::File.get_attributes(path)  # raises if missing

// after
attrs = Puppet::Util::Windows::File.get_attributes(path, false)
missing = attrs == Puppet::Util::Windows::File::INVALID_FILE_ATTRIBUTES
Defensive patterns

Strategy: fallback

Validate before calling

attrs = Puppet::Util::Windows::File.get_attributes(path, false)
if attrs == Puppet::Util::Windows::File::INVALID_FILE_ATTRIBUTES
  # missing OR access-denied - distinguish before deciding
  Puppet.debug("cannot query attributes for #{path}")
end

Try / catch

begin
  attrs = Puppet::Util::Windows::File.get_attributes(path)
rescue Puppet::Util::Windows::Error => e
  raise unless [2, 3, 5].include?(e.code)
  attrs = nil  # treat as absent/inaccessible
end

Prevention

When it happens

Trigger: get_attributes(path) with the default raise_on_invalid=true on a path that does not exist (2/3), a path whose parent directory denies traversal (5), a malformed UNC (\\server\share\...) or drive letter, or a file being deleted concurrently between an existence check and the query.

Common situations: Probing for files under locked-down directories (e.g. other users' profiles) where even attribute queries are denied; race with uninstallers deleting files mid-run; typos in configured paths; tools that assume error == not-found and mask access-denied as missing.

Related errors


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