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

Failed to open '%{path}'

Error message

Failed to open '%{path}'

What it means

Raised by open_file when CreateFileW returns INVALID_HANDLE_VALUE. The file or directory is opened with OPEN_EXISTING plus FILE_FLAG_OPEN_REPARSE_POINT and FILE_FLAG_BACKUP_SEMANTICS, so the call fails outright when the path does not exist, access is denied, or the path cannot be opened in the requested mode. The appended Win32 message (via Puppet::Util::Windows::Error using FFI.errno) tells you which case it is, e.g. 'The system cannot find the file specified' or 'Access is denied'.

Source

Thrown at lib/puppet/util/windows/security.rb:525

    dacl
  end

  # Open an existing file with the specified access mode, and execute a
  # block with the opened file HANDLE.
  def open_file(path, access, &block)
    handle = CreateFileW(
      wide_string(path),
      access,
      FILE::FILE_SHARE_READ | FILE::FILE_SHARE_WRITE,
      FFI::Pointer::NULL, # security_attributes
      FILE::OPEN_EXISTING,
      FILE::FILE_FLAG_OPEN_REPARSE_POINT | FILE::FILE_FLAG_BACKUP_SEMANTICS,
      FFI::Pointer::NULL_HANDLE
    ) # template

    if handle == Puppet::Util::Windows::File::INVALID_HANDLE_VALUE
      raise Puppet::Util::Windows::Error, _("Failed to open '%{path}'") % { path: path }
    end

    begin
      yield handle
    ensure
      FFI::WIN32.CloseHandle(handle) if handle
    end

    # handle has already had CloseHandle called against it, nothing to return
    nil
  end

  # Execute a block with the specified privilege enabled
  def with_privilege(privilege, &block)
    set_privilege(privilege, true)
    yield
  ensure
    set_privilege(privilege, false)

View on GitHub (pinned to e227c27540)

Solutions

  1. Check the appended Win32 text / e.code: 2 = file not found, 5 = access denied, 32 = sharing violation
  2. Verify the path exists at run time (File.exist?) before touching security on it
  3. Run the agent elevated (Administrator) or grant the agent account READ_CONTROL/WRITE_DAC on the target
  4. For long paths, use an absolute path with the \\?\\ prefix or shorten the directory tree

Example fix

// before
Puppet::Util::Windows::Security.get_security_descriptor(path)

# after
unless File.exist?(path)
  raise Puppet::Error, "Cannot manage ACL: #{path} does not exist"
end
Puppet::Util::Windows::Security.get_security_descriptor(path)
Defensive patterns

Strategy: validation

Validate before calling

raise Puppet::Error, "#{path} does not exist" unless File.exist?(path)
# ensure the agent can open it for security reads
accessible = File.readable?(path) rescue false

Try / catch

begin
  Puppet::Util::Windows::Security.get_security_descriptor(path)
rescue Puppet::Util::Windows::Error => e
  case e.code
  when 2 then Puppet.err "#{path} vanished mid-run"
  when 5 then Puppet.err "#{path}: no access; run agent elevated"
  when 32 then Puppet.err "#{path}: sharing violation; retry later"
  end
  raise
end

Prevention

When it happens

Trigger: get_security_descriptor or set_security_descriptor on a path that was deleted between catalog compile and run, a path the agent account cannot open (no READ_CONTROL for reads, no WRITE_DAC/WRITE_OWNER for writes), an invalid/overlong path, or a file exclusively locked with no share flags.

Common situations: Puppet managing a file that another process removes/recreates mid-run; running the agent as a limited user against system-owned files; paths longer than MAX_PATH; antivirus temporarily locking targets.

Related errors


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