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

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

Error message

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

What it means

StringConverter raises this FormatError when formatting a Float with a conversion letter outside 'dxXobBeEfgGaAsp'. Floats accept integer-conversion letters (dxXobB — the value is truncated with val.to_i first), float letters (eEfgGaA), '%p' (Ruby inspect form) and '%s' (quoted inspect form with alt flag). Notably '%c' (character) — valid for Integer — is illegal here; the else at string_converter.rb:768 raises FormatError('Float', f.format, 'dxXobBeEfgGaAsp').

Source

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

    end
  end

  # @api private
  def string_PFloatType(val_type, val, format_map, _)
    f = get_format(val_type, format_map)
    case f.format
    when :d, :x, :X, :o, :b, :B
      Kernel.format(f.orig_fmt, val.to_i)

    when :e, :E, :f, :g, :G, :a, :A, :p
      Kernel.format(f.orig_fmt, val)

    when :s
      float_str = f.alt? ? "\"#{Kernel.format('%p', val)}\"" : Kernel.format('%p', val)
      Kernel.format(f.orig_fmt, float_str)

    else
      raise FormatError.new('Float', f.format, 'dxXobBeEfgGaAsp')
    end
  end

  # @api private
  def string_PBinaryType(val_type, val, format_map, _)
    f = get_format(val_type, format_map)
    substitute = f.alt? ? 'p' : 's'
    case f.format
    when :s
      val_to_convert = val.binary_buffer
      if !f.alt?
        # Assume it is valid UTF-8
        val_to_convert = val_to_convert.dup.force_encoding('UTF-8')
        # If it isn't
        unless val_to_convert.valid_encoding?
          # try to convert and fail with details about what is wrong
          val_to_convert = val.binary_buffer.encode('UTF-8')
        end

View on GitHub (pinned to e227c27540)

Solutions

  1. Use '%f', '%e', '%g' (float forms), '%d' (truncates via to_i) or '%s' for floats
  2. Convert to Integer first if you truly want character output: String(1.5.to_i, '%c')
  3. Whitelist dynamic format letters against %w[d x X o b B e E f g G a A s p]

Example fix

# before
$str = String($ratio, '%c')
# after
$str = String($ratio, '%f')
Defensive patterns

Strategy: validation

Validate before calling

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

Prevention

When it happens

Trigger: `String(1.5, '%c')`, `String($ratio, '%v')`, `String(3.14, '%q')` — any letter not in dxXobBeEfgGaAsp applied to a Float value in DSL `String()` calls or Ruby StringConverter invocations.

Common situations: Reusing an Integer format list for floats and assuming %c carries over; applying per-collection formats to mixed numeric data; porting C printf specs that use %c for ordinals.

Related errors


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