puppetlabs/puppet · error · ArgumentError

Given variables must be a hash, got %{type}

Error message

Given variables must be a hash, got %{type}

What it means

PAL's add_variables injects caller-supplied variables into the evaluation scope. nil is a valid no-op, but any other non-Hash value raises ArgumentError reporting the actual class. The variables hash flows from the PAL entry points (variables: / target_variables: options) into the scope.

Source

Thrown at lib/puppet/pal/pal_impl.rb:378

  # speeded up (as getting a fresh set of facts is avoided in a later step).
  #
  def self.prepare_node_facts(node, facts)
    # Prepare the node with facts if it does not already have them
    if node.facts.nil?
      node_facts = facts.nil? ? nil : Puppet::Node::Facts.new(Puppet[:node_name_value], facts)
      node.fact_merge(node_facts)
      # Add server facts so $server_facts[environment] exists when doing a puppet script
      # SCRIPT TODO: May be needed when running scripts under orchestrator. Leave it for now.
      #
      node.add_server_facts({})
    end
  end
  private_class_method :prepare_node_facts

  def self.add_variables(scope, variables)
    return if variables.nil?
    unless variables.is_a?(Hash)
      raise ArgumentError, _("Given variables must be a hash, got %{type}") % { type: variables.class }
    end

    rich_data_t = Puppet::Pops::Types::TypeFactory.rich_data
    variables.each_pair do |k, v|
      unless k =~ Puppet::Pops::Patterns::VAR_NAME
        raise ArgumentError, _("Given variable '%{varname}' has illegal name") % { varname: k }
      end

      unless rich_data_t.instance?(v)
        raise ArgumentError, _("Given value for '%{varname}' has illegal type - got: %{type}") % { varname: k, type: v.class }
      end

      scope.setvar(k, v)
    end
  end
  private_class_method :add_variables

  # The main routine for script compiler

View on GitHub (pinned to e227c27540)

Solutions

  1. Pass a Ruby Hash: variables: { 'debug' => true }
  2. Convert pair arrays with .to_h or Hash[...] before the call
  3. For JSON input, ensure JSON.parse returned an object ({}), not a scalar/array

Example fix

# before
Puppet::Pal.with_script_compiler(variables: config.to_s) { |c| }

# after
Puppet::Pal.with_script_compiler(variables: config.to_h) { |c| }
Defensive patterns

Strategy: type-guard

Validate before calling

raise ArgumentError, "variables must be a Hash, got #{variables.class}" unless variables.is_a?(Hash)

Type guard

def pal_variables?(v)
  v.nil? || v.is_a?(Hash)
end

Prevention

When it happens

Trigger: variables: 'a=1' (String), variables: [['x', 1]] (array of pairs), or feeding JSON.parse output that is an Array/String directly to with_script_compiler/in_environment variables option.

Common situations: Passing serialized config (JSON/YAML fragments) without converting; .to_s applied to a hash; older tooling that passed key/value lists.

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/1a564a96d18f7e32. Report an issue: GitHub.