puppetlabs/puppet · error · Puppet::Util::Windows::Error
QueryFullProcessImageNameW(phandle, #{use_win32_path_format}
Error message
QueryFullProcessImageNameW(phandle, #{use_win32_path_format}, exe_name_ptr, #{max_chars} What it means
Raised by Process.get_process_image_name_by_pid (lib/puppet/util/windows/process.rb:136) when QueryFullProcessImageNameW returns FALSE. The method already runs under SE_DEBUG_NAME via Security.with_privilege, opens the pid with PROCESS_QUERY_INFORMATION, and sizes the buffer at MAX_PATH_LENGTH + 1 = 32768 wchars, so the realistic failures are: the process exited between OpenProcess and the query (ERROR_INVALID_HANDLE / stale), or the target is a protected process that refuses the query even with SeDebugPrivilege (ERROR_ACCESS_DENIED).
Source
Thrown at lib/puppet/util/windows/process.rb:136
# all handles have been closed, so nothing to safely return
nil
end
module_function :with_process_token
def get_process_image_name_by_pid(pid)
image_name = ''.dup
Puppet::Util::Windows::Security.with_privilege(Puppet::Util::Windows::Security::SE_DEBUG_NAME) do
open_process(PROCESS_QUERY_INFORMATION, false, pid) do |phandle|
FFI::MemoryPointer.new(:dword, 1) do |exe_name_length_ptr|
# UTF is 2 bytes/char:
max_chars = MAX_PATH_LENGTH + 1
exe_name_length_ptr.write_dword(max_chars)
FFI::MemoryPointer.new(:wchar, max_chars) do |exe_name_ptr|
use_win32_path_format = 0
result = QueryFullProcessImageNameW(phandle, use_win32_path_format, exe_name_ptr, exe_name_length_ptr)
if result == FFI::WIN32_FALSE
raise Puppet::Util::Windows::Error, "QueryFullProcessImageNameW(phandle, #{use_win32_path_format}, " \
"exe_name_ptr, #{max_chars}"
end
image_name = exe_name_ptr.read_wide_string(exe_name_length_ptr.read_dword)
end
end
end
end
image_name
end
module_function :get_process_image_name_by_pid
def lookup_privilege_value(name, system_name = '', &block)
FFI::MemoryPointer.new(LUID.size) do |luid_ptr|
result = LookupPrivilegeValueW(
wide_string(system_name),
wide_string(name.to_s),
luid_ptrView on GitHub (pinned to e227c27540)
Solutions
- Rescue Puppet::Util::Windows::Error and treat failure as 'process gone / not inspectable' — return nil and let the caller skip.
- In polling loops, tolerate gaps: the next tick usually succeeds for long-lived processes.
- Confirm the agent runs elevated (SeDebugPrivilege acquirable) when inspecting other sessions' processes.
- Branch on e.code: 6 (invalid handle) means an exit race, 5 (access denied) means a protected process.
Example fix
# before image = Process.get_process_image_name_by_pid(pid) # after — tolerate the exit race begin image = Process.get_process_image_name_by_pid(pid) rescue Puppet::Util::Windows::Error image = nil # process exited or is protected end
Defensive patterns
Strategy: fallback
Try / catch
def safe_image_name(pid)
Process.get_process_image_name_by_pid(pid)
rescue Puppet::Util::Windows::Error => e
Puppet.debug "image lookup failed for pid #{pid} (#{e.code}): #{e.message}"
nil # caller falls back to cached data or skips this tick
end Prevention
- Never assume a pid stays alive across the call — always rescue in monitoring loops
- Run inventory agents as SYSTEM so SE_DEBUG_NAME can be enabled
- Debounce: skip pids seen for the first time to avoid racing process startup and teardown
When it happens
Trigger: Polling the image name of short-lived processes that vanish mid-call; querying protected-process-light binaries such as antivirus or lsass; the caller lacking the ability to acquire SeDebugPrivilege (not elevated), which surfaces when targeting other sessions' processes.
Common situations: Process-monitoring loops racing process exit; agents checking which executable owns a lock or a port; inventory scripts hitting protected services.
Related errors
- OpenProcess(#{desired_access.to_s(8)}, #{inherit}, #{process
- CreateSymbolicLink(#{symlink}, #{target}, #{flags.to_s(8)})
- Failed to get child process exit code
- GetTokenInformation(#{token_handle}, #{token_information}, #
- ReplaceFile(#{target}, #{source})
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/1a127818bd2aae59.
Report an issue: GitHub.