{"record":{"id":"7c12a4fc92889758","repo":"puppetlabs/puppet","slug":"value-of-type-type-cannot-be-converted-to-hash","errorCode":null,"errorMessage":"Value of type %{type} cannot be converted to Hash","messagePattern":"Value of type %(.+?) cannot be converted to Hash","errorType":"exception","errorClass":"TypeConversionError","httpStatus":null,"severity":"error","filePath":"lib/puppet/pops/types/types.rb","lineNumber":2861,"sourceCode":"        case from\n        when Array\n          if from.size == 0\n            {}\n          else\n            unless from.size.even?\n              raise TypeConversionError, _('odd number of arguments for Hash')\n            end\n\n            Hash[*from]\n          end\n        when Hash\n          from\n        else\n          if PIterableType::DEFAULT.instance?(from)\n            Hash[*Iterable.on(from).to_a]\n          else\n            t = TypeCalculator.singleton.infer(from).generalize\n            raise TypeConversionError, _(\"Value of type %{type} cannot be converted to Hash\") % { type: t }\n          end\n        end\n      end\n    end\n  end\n\n  DEFAULT = PHashType.new(nil, nil)\n  KEY_PAIR_TUPLE_SIZE = PIntegerType.new(2, 2)\n  DEFAULT_KEY_PAIR_TUPLE = PTupleType.new([PUnitType::DEFAULT, PUnitType::DEFAULT], KEY_PAIR_TUPLE_SIZE)\n  EMPTY = PHashType.new(PUnitType::DEFAULT, PUnitType::DEFAULT, PIntegerType.new(0, 0))\n\n  protected\n\n  # Hash is assignable if o is a Hash and o's key and element types are assignable\n  # @api private\n  def _assignable?(o, guard)\n    case o\n    when PHashType","sourceCodeStart":2843,"sourceCodeEnd":2879,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/pops/types/types.rb#L2843-L2879","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before (Puppet DSL)\ndefine foo($options) {\n  $h = Hash.new($options)   # TypeConversionError when $options is a scalar\n}\n\n# after\ndefine foo(Hash $options = {}) {\n  $h = $options   # bad shapes are rejected at compile time\n}","handlingStrategy":"type-guard","validationCode":"# Ruby\nok = value.is_a?(Hash) || (value.is_a?(Array) && value.size.even?)\n\n# Puppet DSL\nunless $x =~ Variant[Hash, Array] { fail('expected Hash or Array') }","typeGuard":"def hash_convertible?(v)\n  v.is_a?(Hash) || v.is_a?(Array) || v.is_a?(Enumerable)\nend","tryCatchPattern":"begin\n  Hash.new($x)\nrescue Puppet::Error => e\n  fail(\"cannot convert ${x} to Hash: ${e.message}\")\nend","preventionTips":["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."],"tags":["puppet","hash","type-conversion","data-validation"],"backgroundTag":"type-conversion-failed","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}