puppetlabs/puppet · error · TypeError

hash keyword arguments expected

Error message

hash keyword arguments expected

What it means

The Process.create monkey patch takes exactly one argument - a Hash of options - and validate_args raises TypeError('hash keyword arguments expected') when it receives anything else. This mirrors the win32-process gem API (Process.create(command_line: 'cmd') passes one Hash). It is a call-shape mistake, raised before any validation of contents or any Win32 call.

Source

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

      end

      0
    end

    private

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

    def validate_args(args)
      raise TypeError, 'hash keyword arguments expected' unless args.is_a?(Hash)
    end

    def validate_keys(args)
      args.each do |key, val|
        key = key.to_s.to_sym
        raise ArgumentError, "invalid key '#{key}'" unless VALID_KEYS.include?(key)

        hash[key] = val
      end
    end

    def validate_startup_info
      hash[:startup_info].each do |key, val|
        key = key.to_s.to_sym
        raise ArgumentError, "invalid startup_info key '#{key}'" unless VALID_SI_KEYS.include?(key)

        si_hash[key] = val
      end

View on GitHub (pinned to e227c27540)

Solutions

  1. Pass a single Hash: Process.create(command_line: 'cmd /c dir')
  2. Collect kwargs with a double splat (def wrapper(**opts); Process.create(opts); end) so an opts Hash is always forwarded
  3. Coerce early: raise TypeError in your own wrapper unless args.is_a?(Hash)

Example fix

// before
Process.create('notepad.exe')            # String -> TypeError
Process.create(:command_line, 'notepad')  # two args -> TypeError

// after
Process.create(command_line: 'notepad.exe')  # single Hash argument
Defensive patterns

Strategy: type-guard

Validate before calling

raise TypeError, 'Process.create expects a single options Hash' unless args.is_a?(Hash)
Process.create(args)

Type guard

def create_options?(value)
  value.is_a?(Hash)
end

Try / catch

begin
  info = Process.create(opts)
rescue TypeError => e
  raise unless e.message.include?('hash keyword arguments expected')
  raise 'wrap variadic input into a Hash first: Process.create(command_line: cmd)'
end

Prevention

When it happens

Trigger: Calling Process.create('cmd /c dir') with a positional string; passing nil, an Array of pairs, or two separate arguments; under Ruby 3, calling a wrapper defined as def spawn(**opts) that forwards nothing when opts is empty; splatting incorrectly (Process.create(*args) where args is not a single Hash).

Common situations: Code written against Ruby's Process.spawn (variadic) reused with win32-style Process.create; ERB/liquid templates interpolating a string command; API wrappers that accept either form and forward blindly.

Understand the failure class

Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.

Related errors


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