puppetlabs/puppet · error · ArgumentError

The %{name} property must be specified as a hash or an array

Error message

The %{name} property must be specified as a hash or an array of key/value pairs (strings)!

What it means

Puppet::Property::KeyValue is a base class for properties holding key/value settings (strings like 'k=v' or a Hash). Its validate block accepts only a String or a Hash; any other object - Integer, Array of non-strings, nil - raises ArgumentError demanding 'a hash or an array of key/value pairs (strings)'. Puppet casts should-values to arrays, so the block runs per element: one bad element fails the whole property value.

Source

Thrown at lib/puppet/property/keyvalue.rb:133

          :absent
        end
      end

      # Returns true if there is no _is_ value, else returns if _is_ is equal to _should_ using == as comparison.
      # @return [Boolean] whether the property is in sync or not.
      def insync?(is)
        return true unless is

        (is == should)
      end

      # We only accept an array of key/value pairs (strings), a single
      # key/value pair (string) or a Hash as valid values for our property.
      # Note that for an array property value, the 'value' passed into the
      # block corresponds to the array element.
      validate do |value|
        unless value.is_a?(String) || value.is_a?(Hash)
          raise ArgumentError, _("The %{name} property must be specified as a hash or an array of key/value pairs (strings)!") % { name: name }
        end

        next if value.is_a?(Hash)

        unless value.include?(separator.to_s)
          raise ArgumentError, _("Key/value pairs must be separated by '%{separator}'") % { separator: separator }
        end
      end

      # The validate step ensures that our passed-in value is
      # either a String or a Hash. If our value's a string,
      # then nothing else needs to be done. Otherwise, we need
      # to stringify the hash's keys and values to match our
      # internal representation of the property's value.
      munge do |value|
        next value if value.is_a?(String)

        munged_value = value.to_a.map! do |hash_key, hash_value|

View on GitHub (pinned to e227c27540)

Solutions

  1. Pass strings formatted as key<separator>value: attrs => 'answer=42'.
  2. Pass a single Hash when the property supports it: attrs => { 'answer' => '42' }.
  3. Validate and coerce the parameter before it reaches the resource.

Example fix

# before (Puppet DSL)
mytype { 'x': attrs => 42 }            # ArgumentError

# after
mytype { 'x': attrs => 'answer=42' }   # or attrs => { 'answer' => '42' }
Defensive patterns

Strategy: validation

Validate before calling

# Ruby
ok = value.is_a?(String) || value.is_a?(Hash)

# Puppet DSL: constrain the parameter
Variant[String, Hash] $attrs = {}

Type guard

def keyvalue_shaped?(v)
  v.is_a?(String) || v.is_a?(Hash)
end

Prevention

When it happens

Trigger: Setting a KeyValue-derived property to a number (attrs => 42), an array of numbers, or undef; passing nested structures where flat 'k=v' strings or a single Hash were expected.

Common situations: Hiera data storing numbers without quotes (or over-quoted strings); users assuming structured input; modules whose documentation is unclear about the accepted shape.

Related errors


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