puppetlabs/puppet · error · ArgumentError
#{my_caller.class}(): wrong argument type (#{obj.class}; is
Error message
#{my_caller.class}(): wrong argument type (#{obj.class}; is not Iterable. What it means
All of Puppet's iteration functions (each, map, filter, reduce, all, any, slice, step, reverse_each, index) obtain their iterator through Iterable.asserted_iterable. Iterable.on returns nil for anything that is not a String, Array, Hash, non-negative Integer, integer/string Range, Dir, Iterable/IteratorProducer, or the corresponding Puppet types (PIntegerType, PEnumType); asserted_iterable turns that nil into an ArgumentError naming the calling function.
Source
Thrown at lib/puppet/pops/types/iterable.rb:36
# `Integer` - when positive, yields each value from zero to the given number
# `PIntegerType` - yields each element from min to max (inclusive) provided min < max and neither is unbounded.
# `PEnumtype` - yields each possible value of the enum.
# `Range` - yields an iterator for all elements in the range provided that the range start and end
# are both integers or both strings and start is less than end using natural ordering.
# `Dir` - yields each name in the directory
#
# An `ArgumentError` is raised for all other objects.
#
# @param my_caller [Object] The calling object to reference in errors
# @param obj [Object] The object to produce an `Iterable` for
# @param infer_elements [Boolean] Whether or not to recursively infer all elements of obj. Optional
#
# @return [Iterable,nil] The produced `Iterable`
# @raise [ArgumentError] In case an `Iterable` cannot be produced
# @api public
def self.asserted_iterable(my_caller, obj, infer_elements = false)
iter = on(obj, nil, infer_elements)
raise ArgumentError, "#{my_caller.class}(): wrong argument type (#{obj.class}; is not Iterable." if iter.nil?
iter
end
# Produces an `Iterable` for one of the following types with the following characteristics:
#
# `String` - yields each character in the string
# `Array` - yields each element in the array
# `Hash` - yields each key/value pair as a two element array
# `Integer` - when positive, yields each value from zero to the given number
# `PIntegerType` - yields each element from min to max (inclusive) provided min < max and neither is unbounded.
# `PEnumtype` - yields each possible value of the enum.
# `Range` - yields an iterator for all elements in the range provided that the range start and end
# are both integers or both strings and start is less than end using natural ordering.
# `Dir` - yields each name in the directory
#
# The value `nil` is returned for all other objects.
#View on GitHub (pinned to e227c27540)
Solutions
- Give the value a safe default before iterating: $items = pick_default($lookup, []) (or `unless $x == undef` guards) so the argument is always a real Array/Hash.
- Convert the value to an iterable kind first: Integer($n) for a numeric loop, .to_a for a range-like value, Sensitive.unwrap for sensitive data.
- Verify the producer of the value (hiera function, custom function) really returns the collection type you expect at every code path.
Example fix
# before
each($lookup('services', undef)) {|s| notify { $s } }
# after
$services = pick($lookup('services', undef), [])
each($services) {|s| notify { $s } } Defensive patterns
Strategy: type-guard
Validate before calling
# Ruby — use the non-raising factory and check for nil
iter = Puppet::Pops::Types::Iterable.on(obj)
raise ArgumentError, "#{obj.inspect} is not iterable" if iter.nil? Type guard
# Puppet — restrict the parameter to iterable kinds
function mymap(Variant[Collection, String, Integer[0, default]] $enum) { ... }
# Ruby — cheap structural guard
def iterable?(o)
o.is_a?(String) || o.is_a?(Array) || o.is_a?(Hash) ||
(o.is_a?(Integer) && o >= 0) || o.is_a?(Range) ||
Puppet::Pops::Types::Iterable.on(o) != nil
end Try / catch
begin
Puppet::Pops::Types::Iterable.asserted_iterable(self, obj)
rescue ArgumentError => e
fail("expected Array/Hash/String/Integer, got #{obj.class}: #{e.message}")
end Prevention
- Type iteration parameters as Collection/Array[...] in custom functions instead of Any.
- Default lookups that feed iteration: pick($x, []) or a dedicated key with a guaranteed array.
When it happens
Trigger: Passing a non-iterable first argument to an iteration function: each(1.5) {|x| ... }, map(true) {|x| ... }, each(undef) {...}, or iterating a value whose lookup/function call returned nil, a Float, a Boolean, or an arbitrary object. Also direct Ruby calls to Iterable.asserted_iterable(caller, obj) with such values.
Common situations: A hiera lookup or resource attribute expected to be an array comes back undef; a function returns Float or Boolean instead of Integer; iterating a Sensitive value without unwrapping; treating a single scalar like an array after a bad conditional.
Related errors
- Init cannot be parameterized with an undefined type and addi
- 'from' must be less or equal to 'to'. Got (#{from}, #{to}
- Please provide a file or checksum to diff with
- Failed to diff files
- Unsupported translation file format #{file_format}; please u
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/f66a3a62128e2dd2.
Report an issue: GitHub.