puppetlabs/puppet · error · SystemCallError

SetPriorityClass

Error message

SetPriorityClass

What it means

In Process.setpriority, after OpenProcess succeeds, SetPriorityClass is invoked and a falsy result raises SystemCallError('SetPriorityClass', FFI.errno). Because the monkey patch forwards the value untouched to Windows, passing anything that is not a valid priority-class constant - most commonly Unix nice numbers like -5 or 10 - fails here (usually ERROR_INVALID_PARAMETER, 87).

Source

Thrown at lib/puppet/util/windows/monkey_patches/process.rb:195

    # * Process::REALTIME_PRIORITY_CLASS
    # * Process::BELOW_NORMAL_PRIORITY_CLASS
    # * Process::ABOVE_NORMAL_PRIORITY_CLASS

    def setpriority(kind, int, int_priority)
      raise TypeError unless kind.is_a?(Integer)
      raise TypeError unless int.is_a?(Integer)
      raise TypeError unless int_priority.is_a?(Integer)

      int = Process.pid if int == 0
      handle = OpenProcess(PROCESS_SET_INFORMATION, 0, int)

      if handle == 0
        raise SystemCallError, FFI.errno, "OpenProcess"
      end

      begin
        result = SetPriorityClass(handle, int_priority)
        raise SystemCallError, FFI.errno, "SetPriorityClass" unless result
      ensure
        FFI::WIN32.CloseHandle(handle)
      end

      0
    end

    private

    def initialize_defaults
      @hash = {
        app_name: nil,
        creation_flags: 0,
        close_handles: true
      }
      @si_hash = nil
      @procinfo = nil
    end

View on GitHub (pinned to e227c27540)

Solutions

  1. Pass Windows priority-class constants: Process::IDLE_PRIORITY_CLASS, :BELOW_NORMAL/:NORMAL/:ABOVE_NORMAL_PRIORITY_CLASS, :HIGH_PRIORITY_CLASS, :REALTIME_PRIORITY_CLASS
  2. Translate Unix nice values explicitly (e.g. nice>0 -> BELOW_NORMAL, nice<0 -> ABOVE_NORMAL) before calling
  3. Rescue SystemCallError and skip - never let priority tuning abort the main work

Example fix

// before
Process.setpriority(:process, pid, 10)  # Unix nice value -> SetPriorityClass fails

// after
Process.setpriority(:process, pid, Process::BELOW_NORMAL_PRIORITY_CLASS)
Defensive patterns

Strategy: validation

Validate before calling

VALID_PRIORITIES = [Process::IDLE_PRIORITY_CLASS, Process::BELOW_NORMAL_PRIORITY_CLASS,
                    Process::NORMAL_PRIORITY_CLASS, Process::ABOVE_NORMAL_PRIORITY_CLASS,
                    Process::HIGH_PRIORITY_CLASS, Process::REALTIME_PRIORITY_CLASS].freeze
raise ArgumentError, "not a Windows priority class: #{int_priority}" unless VALID_PRIORITIES.include?(int_priority)
Process.setpriority(:process, pid, int_priority)

Type guard

def priority_class?(value)
  [Process::IDLE_PRIORITY_CLASS, Process::BELOW_NORMAL_PRIORITY_CLASS,
   Process::NORMAL_PRIORITY_CLASS, Process::ABOVE_NORMAL_PRIORITY_CLASS,
   Process::HIGH_PRIORITY_CLASS, Process::REALTIME_PRIORITY_CLASS].include?(value)
end

Try / catch

begin
  Process.setpriority(:process, pid, int_priority)
rescue SystemCallError => e
  raise unless e.message.include?('SetPriorityClass')
  warn "skipping priority change for #{pid}: #{e.message}"
end

Prevention

When it happens

Trigger: Process.setpriority(:process, pid, -5) or (…, 10) using Unix nice semantics; passing 0 or nil as the priority; a REALTIME_PRIORITY_CLASS request from a low-privilege token; a handle whose PROCESS_SET_INFORMATION access was stripped between open and set.

Common situations: Porting Unix scheduling scripts ('nice -n 5') to Windows via this API; config files carrying nice values fed verbatim to setpriority; JRuby/Windows CI differences where the same helper works on Linux.

Related errors


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