puppetlabs/puppet · error · Puppet::Pops::Types::StringConverter::FormatError

Illegal format '#{actual}' specified for value of Hash type

Error message

Illegal format '#{actual}' specified for value of Hash type - expected one of the characters 'hasp'

What it means

StringConverter raises this FormatError when formatting a Hash (or Struct, which delegates to string_PHashType) with a container format letter outside 'hasp': 'h' (key => value rendering with per-key/per-value formats), 'a' (array-of-pairs rendering), 's' and 'p' (string/Puppet-notation forms). The else at string_converter.rb:1094 raises FormatError('Hash', format.format, 'hasp'). Struct values follow the same rule since string_PStructType forwards here.

Source

Thrown at lib/puppet/pops/types/string_converter.rb:1094

        padding = children_indentation.padding
      end
      buf << delims[0]
      buf << cond_break # break after opening delimiter if pretty printing
      buf << val.map do |k, v|
        key_type = TypeCalculator.infer_set(k)
        val_type = TypeCalculator.infer_set(v)
        key = _convert(key_type, k, is_container?(key_type) ? format_map : string_formats, children_indentation)
        val = _convert(val_type, v, is_container?(val_type) ? format_map : string_formats, children_indentation)
        "#{padding}#{key}#{assoc}#{val}"
      end.join(sep)
      if format.alt?
        buf << cond_break
        buf << indentation.padding
      end
      buf << delims[1]
      buf
    else
      raise FormatError.new('Hash', format.format, 'hasp')
    end
  end

  # @api private
  def string_PStructType(val_type, val, format_map, indentation)
    string_PHashType(val_type, val, format_map, indentation)
  end

  # @api private
  def string_PTypeType(val_type, val, format_map, _)
    f = get_format(val_type, format_map)
    case f.format
    when :s
      str_val = f.alt? ? "\"#{val}\"" : val.to_s
      Kernel.format(f.orig_fmt, str_val)
    when :p
      Kernel.format(f.orig_fmt.tr('p', 's'), val.to_s)
    else

View on GitHub (pinned to e227c27540)

Solutions

  1. Use '%h' for key => value output, '%a' for array-of-pairs, '%s'/'%p' for plain forms
  2. Specify key/value element formats inside the container format options rather than as the leading letter
  3. Whitelist the container letter against %w[h a s p]

Example fix

# before
$str = String({a => 1}, '%d')
# after
$str = String({a => 1}, '%h')
Defensive patterns

Strategy: validation

Validate before calling

fmt = '%d'
letter = fmt[/\A%[#\-+ 0\d.]*([a-zA-Z])\z/, 1]
raise ArgumentError, "#{fmt} invalid for Hash/Struct (container letter must be h/a/s/p)" unless %w[h a s p].include?(letter)

Prevention

When it happens

Trigger: `String({a => 1}, '%d')` — scalar letter used as container letter; likewise for Struct-typed values. Per-key and per-value formats belong inside the container format specification, not as the leading letter.

Common situations: Pretty-printing option hashes for logs/reports and copying a value format as the top-level letter; converting Struct-validated data with a format designed for its values.

Related errors


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