puppetlabs/puppet · error · Puppet::Util::Windows::Error
GetTokenInformation(#{token_handle}, #{token_information}, n
Error message
GetTokenInformation(#{token_handle}, #{token_information}, nil, 0, #{return_length_ptr}) What it means
Raised by Process.get_token_information (lib/puppet/util/windows/process.rb:176) when the sizing pass of GetTokenInformation leaves return_length <= 0. The code infers failure from the length rather than the return BOOL, so this means the first call accomplished nothing: the token handle is invalid or closed, lacks TOKEN_QUERY access, or the token information class passed is not valid on this OS.
Source
Thrown at lib/puppet/util/windows/process.rb:176
raise Puppet::Util::Windows::Error, "LookupPrivilegeValue(#{system_name}, #{name}, #{luid_ptr})"
end
yield LUID.new(luid_ptr)
end
# the underlying MemoryPointer for LUID is cleaned up by this point
nil
end
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
nilView on GitHub (pinned to e227c27540)
Solutions
- Keep all token reads inside the open_process_token block — the handle's lifetime is that block.
- Open the token with TOKEN_QUERY included (TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES when adjusting privileges).
- Verify the token information class (e.g. :TokenUser, :TokenPrivileges, :TokenElevation) is spelled and valued correctly.
- Rescue and inspect e.code — 6 (invalid handle) points at lifetime bugs, 5 (access denied) at the mask.
Example fix
# before — handle escapes its block and is already closed
Process.open_process_token(h, 0x20) { |t| saved = t }
Process.get_token_information(saved, :TokenUser)
# after — query inside the block, with TOKEN_QUERY
Process.open_process_token(h, Process::TOKEN_QUERY | 0x20) do |t|
Process.get_token_information(t, :TokenUser) { |buf| use(buf) }
end Defensive patterns
Strategy: try-catch
Validate before calling
# ensure the access mask includes TOKEN_QUERY before any information read
mask |= Process::TOKEN_QUERY if (mask & Process::TOKEN_QUERY).zero?
Process.open_process_token(handle, mask) { |t| Process.get_token_information(t, info_class) { |b| use(b) } } Try / catch
begin
Process.get_token_information(token, info_class) { |buf| use(buf) }
rescue Puppet::Util::Windows::Error => e
Puppet.err "token query #{info_class} failed (#{e.code}): #{e.message}"
nil
end Prevention
- Never let a token handle outlive its open_process_token block
- Always include TOKEN_QUERY in the access mask when reading token information
- Pin the token class list to the oldest Windows version you support
When it happens
Trigger: Passing a token handle that has already been closed (open_process_token closes it when its block ends); opening a token with only TOKEN_ADJUST_PRIVILEGES and then reading information from it; requesting a Token* class unsupported on the Windows version; passing a bogus class symbol.
Common situations: Saving the token handle into a variable used after the open_process_token block; privilege-enabling code that never asks for TOKEN_QUERY; version drift in token class names/values.
Related errors
- Failed to get child process exit code
- OpenProcessToken(#{handle}, #{desired_access.to_s(8)}, #{tok
- GetTokenInformation(#{token_handle}, #{token_information}, #
- ReplaceFile(#{target}, #{source})
- MoveFileEx(#{source}, #{target}, #{flags.to_s(8)})
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/02493d26e3323ab7.
Report an issue: GitHub.