puppetlabs/puppet · error · TypeConversionError
Value of type %{type} cannot be converted to Hash
Error message
Value of type %{type} cannot be converted to Hash What it means
Hash.new converts a Hash directly, an Array via flattening, and any other value only if it is iterable (PIterableType::DEFAULT.instance?(from)). A scalar such as an Integer, Boolean or Undef cannot become a hash, so the conversion raises TypeConversionError naming the inferred type of the value. The guard runs before any partial result is produced.
Source
Thrown at lib/puppet/pops/types/types.rb:2861
case from
when Array
if from.size == 0
{}
else
unless from.size.even?
raise TypeConversionError, _('odd number of arguments for Hash')
end
Hash[*from]
end
when Hash
from
else
if PIterableType::DEFAULT.instance?(from)
Hash[*Iterable.on(from).to_a]
else
t = TypeCalculator.singleton.infer(from).generalize
raise TypeConversionError, _("Value of type %{type} cannot be converted to Hash") % { type: t }
end
end
end
end
end
DEFAULT = PHashType.new(nil, nil)
KEY_PAIR_TUPLE_SIZE = PIntegerType.new(2, 2)
DEFAULT_KEY_PAIR_TUPLE = PTupleType.new([PUnitType::DEFAULT, PUnitType::DEFAULT], KEY_PAIR_TUPLE_SIZE)
EMPTY = PHashType.new(PUnitType::DEFAULT, PUnitType::DEFAULT, PIntegerType.new(0, 0))
protected
# Hash is assignable if o is a Hash and o's key and element types are assignable
# @api private
def _assignable?(o, guard)
case o
when PHashTypeView on GitHub (pinned to e227c27540)
Solutions
- Declare the parameter as Hash in the class/defined type so validation fails at compile time with a clear message.
- Give the parameter a Hash default and merge instead of converting: $opts = {}.merge($options).
- Convert explicitly only after checking the input is a Hash or an even-length Array.
Example fix
# before (Puppet DSL)
define foo($options) {
$h = Hash.new($options) # TypeConversionError when $options is a scalar
}
# after
define foo(Hash $options = {}) {
$h = $options # bad shapes are rejected at compile time
} Defensive patterns
Strategy: type-guard
Validate before calling
# Ruby
ok = value.is_a?(Hash) || (value.is_a?(Array) && value.size.even?)
# Puppet DSL
unless $x =~ Variant[Hash, Array] { fail('expected Hash or Array') } Type guard
def hash_convertible?(v) v.is_a?(Hash) || v.is_a?(Array) || v.is_a?(Enumerable) end
Try / catch
begin
Hash.new($x)
rescue Puppet::Error => e
fail("cannot convert ${x} to Hash: ${e.message}")
end Prevention
- Type parameters as Hash (or Optional[Hash]) instead of accepting Variant and converting later.
- Default hash parameters to {} and merge; never convert.
- Assert data shape at module boundaries with parameter types or assert_type.
When it happens
Trigger: Hash.new(42), Hash.new(true) or Hash.new(undef) in a manifest; a variable that is sometimes a scalar flowing into a hash-conversion chain; Ruby-side conversion of a non-iterable object via the Hash type's new function.
Common situations: Unvalidated module parameters where the user supplies a string or number where a hash was expected; Hiera lookups returning scalars on fallback paths; data-shape assumptions breaking across module versions.
Related errors
- odd number of arguments for Hash
- Illegal format '#{actual}' specified for value of Hash type
- Unable to convert a #{version_range.class.name} to a SemVerR
- Unable to convert a #{version.class.name} to a SemVer
- Unable to create a #{impl_class.name} from a #{arg.class.nam
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/7c12a4fc92889758.
Report an issue: GitHub.