puppetlabs/puppet · error · Puppet::Util::Windows::Error
GetTokenInformation(#{token_handle}, #{token_information}, #
Error message
GetTokenInformation(#{token_handle}, #{token_information}, #{token_information_buf}, #{return_length}, #{return_length_ptr}) What it means
The second failure mode of Process.get_token_information (lib/puppet/util/windows/process.rb:185): the sizing call succeeded (return_length > 0) but the follow-up GetTokenInformation with the allocated buffer returned FALSE. Something changed between the two back-to-back calls — the handle was closed concurrently, or the token was invalidated as its owning process exited. Usually a transient race rather than a permanent condition.
Source
Thrown at lib/puppet/util/windows/process.rb:185
module_function :lookup_privilege_value
def get_token_information(token_handle, token_information, &block)
# to determine buffer size
FFI::MemoryPointer.new(:dword, 1) do |return_length_ptr|
result = GetTokenInformation(token_handle, token_information, nil, 0, return_length_ptr)
return_length = return_length_ptr.read_dword
if return_length <= 0
raise Puppet::Util::Windows::Error, "GetTokenInformation(#{token_handle}, #{token_information}, nil, 0, #{return_length_ptr})"
end
# re-call API with properly sized buffer for all results
FFI::MemoryPointer.new(return_length) do |token_information_buf|
result = GetTokenInformation(token_handle, token_information,
token_information_buf, return_length, return_length_ptr)
if result == FFI::WIN32_FALSE
raise Puppet::Util::Windows::Error, "GetTokenInformation(#{token_handle}, #{token_information}, #{token_information_buf}, " \
"#{return_length}, #{return_length_ptr})"
end
yield token_information_buf
end
end
# GetTokenInformation buffer has been cleaned up by this point, nothing to return
nil
end
module_function :get_token_information
def parse_token_information_as_token_privileges(token_information_buf)
raw_privileges = TOKEN_PRIVILEGES.new(token_information_buf)
privileges = { :count => raw_privileges[:PrivilegeCount], :privileges => [] }
offset = token_information_buf + TOKEN_PRIVILEGES.offset_of(:Privileges)
privilege_ptr = FFI::Pointer.new(LUID_AND_ATTRIBUTES, offset)View on GitHub (pinned to e227c27540)
Solutions
- Retry the whole query once — this failure is usually a transient race.
- Eliminate sharing: open a fresh token per thread or consumer instead of passing handles around.
- Keep the query inside the open_process_token block so the handle cannot be closed mid-flight.
- Read e.code to distinguish handle races (6) from access problems (5).
Example fix
# before — one shot, fails intermittently under threads
Process.get_token_information(token, :TokenPrivileges) { |buf| use(buf) }
# after — one bounded retry
begin
Process.get_token_information(token, :TokenPrivileges) { |buf| use(buf) }
rescue Puppet::Util::Windows::Error
sleep 0.01
Process.get_token_information(token, :TokenPrivileges) { |buf| use(buf) }
end Defensive patterns
Strategy: retry
Try / catch
attempts = 0
begin
attempts += 1
Process.get_token_information(token, info_class) { |buf| yield buf }
rescue Puppet::Util::Windows::Error => e
retry if attempts < 2 && e.code == 6 # transient handle race
raise
end Prevention
- Do not share token handles across threads — open one per consumer
- Retry once on ERROR_INVALID_HANDLE races before surfacing the error
- Keep queries within the open_process_token block
When it happens
Trigger: The token handle being closed concurrently while get_token_information runs (threads sharing handles); the owning process exiting mid-query; the buffer sized from a return_length that went stale between calls.
Common situations: Multithreaded code sharing one token handle across workers; intermittent failures under load that a retry fixes; long-lived handles stashed from an earlier open instead of being re-opened.
Related errors
- OpenProcess(#{desired_access.to_s(8)}, #{inherit}, #{process
- OpenProcessToken(#{handle}, #{desired_access.to_s(8)}, #{tok
- QueryFullProcessImageNameW(phandle, #{use_win32_path_format}
- GetTokenInformation(#{token_handle}, #{token_information}, n
- ReplaceFile(#{target}, #{source})
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/3c520fc75a806a69.
Report an issue: GitHub.