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

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

Error message

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

What it means

StringConverter raises this FormatError when formatting an Undef value (nil in Puppet, `undef` in DSL) with a format letter outside the wide set 'nudxXobBeEfgGaAvVsp'. Undef is special-cased to render as 'nil'/'null' (n), 'NaN' for numeric letters (dxXobBeEfgGaA), 'n/a'/'N/A' (v/V), ''/'""' (s) and 'undef'/'"undef"' (p); everything else hits the else at string_converter.rb:661. This is the most permissive member of the format family because undef can legitimately stand in for any scalar.

Source

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

  def string_PUndefType(val_type, val, format_map, _)
    f = get_format(val_type, format_map)
    apply_string_flags(f, case f.format
                          when :n
                            f.alt? ? 'null' : 'nil'
                          when :u
                            f.alt? ? 'undefined' : 'undef'
                          when :d, :x, :X, :o, :b, :B, :e, :E, :f, :g, :G, :a, :A
                            'NaN'
                          when :v
                            'n/a'
                          when :V
                            'N/A'
                          when :s
                            f.alt? ? '""' : ''
                          when :p
                            f.alt? ? '"undef"' : 'undef'
                          else
                            raise FormatError.new('Undef', f.format,
                                                  'nudxXobBeEfgGaAvVsp')
                          end)
  end

  # @api private
  def string_PBooleanType(val_type, val, format_map, indentation)
    f = get_format(val_type, format_map)
    case f.format
    when :t
      # 'true'/'false' or 't'/'f' if in alt mode
      str_bool = val.to_s
      apply_string_flags(f, f.alt? ? str_bool[0] : str_bool)

    when :T
      # 'True'/'False' or 'T'/'F' if in alt mode
      str_bool = val.to_s.capitalize
      apply_string_flags(f, f.alt? ? str_bool[0] : str_bool)

View on GitHub (pinned to e227c27540)

Solutions

  1. Use '%s' (empty string / quoted with #) or '%n' ('nil') for undef
  2. Default the variable first: String($x | default { 'n/a' }, '%s') or `$x = pick($x, 'n/a')`
  3. Validate format letters against the allowed set when formats are dynamic

Example fix

# before
$str = String($maybe_undef, '%t')
# after
$str = String($maybe_undef, '%s')
Defensive patterns

Strategy: validation

Validate before calling

fmt = '%t'
letter = fmt[/\A%[#\-+ 0\d.]*([a-zA-Z])\z/, 1]
raise ArgumentError, "#{fmt} invalid for undef" unless %w[n u d x X o b B e E f g G a A v V s p].include?(letter)

Prevention

When it happens

Trigger: `String(undef, '%t')`, `String(undef, '%c')`, `String(undef, '%h')` — any letter not in nudxXobBeEfgGaAvVsp; commonly a format like '%q' (legal for Object but not Undef) applied to an optional variable that is undef.

Common situations: Formatting optional data from Hiera where a lookup returns undef and the code applies a fixed format meant for present values; '%v' works for undef but '%t' or '%q' does not, surprising developers migrating between type-specific formats.

Related errors


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