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

  1. Retry the whole query once — this failure is usually a transient race.
  2. Eliminate sharing: open a fresh token per thread or consumer instead of passing handles around.
  3. Keep the query inside the open_process_token block so the handle cannot be closed mid-flight.
  4. 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

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


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