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

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

Error message

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

What it means

StringConverter raises this FormatError when formatting an Array with a container format letter outside 'asp': 'a' (angle/normal array rendering with per-element formats), 's' (plain to_s style) and 'p' (Puppet-notation, quoted elements). Container formats also carry separator/delimiter options parsed from the format string, but the leading letter itself must be a/s/p; otherwise the else at string_converter.rb:1015 raises FormatError('Array', format.format, 'asp').

Source

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

        else
          buf << sep
          # if break on each (and breaking will not occur because next is an array or hash)
          # or, if indenting, and previous was an array or hash, then break and continue on next line
          # indented.
          if (sz_break && !is_a_or_h?(v)) || (format.alt? && i > 0 && is_a_or_h?(val[i - 1]) && !is_a_or_h?(v))
            buf.rstrip! unless buf[-1] == "\n"
            buf << "\n"
            buf << children_indentation.padding
          end
        end
        # remove trailing space added by separator if followed by break
        buf.rstrip! if buf[-1] == ' ' && str_val[0] == "\n"
        buf << str_val
      end
      buf << delims[1]
      buf
    else
      raise FormatError.new('Array', format.format, 'asp')
    end
  end

  def is_a_or_h?(x)
    x.is_a?(Array) || x.is_a?(Hash)
  end

  def is_container?(t)
    case t
    when PArrayType, PHashType, PStructType, PTupleType, PObjectType
      true
    else
      false
    end
  end

  # @api private
  def string_PTupleType(val_type, val, format_map, indentation)

View on GitHub (pinned to e227c27540)

Solutions

  1. Use '%a' for array formatting and put element formats in the container options, e.g. String($arr, '%a') or with per-element format via the container syntax
  2. Use '%s' for simple rendering or '%p' for Puppet-notation output
  3. Whitelist the container letter against %w[a s p]

Example fix

# before
$str = String([1, 2, 3], '%d')
# after
$str = String([1, 2, 3], '%a')
Defensive patterns

Strategy: validation

Validate before calling

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

Prevention

When it happens

Trigger: `String([1,2,3], '%d')` — applying a scalar format as the container letter; in general any `String($array, '<letter>...')` where the letter is not a/s/p. Note per-element formats are specified inside the container format (e.g. '%(d, )' style); putting the element format first is the classic mistake.

Common situations: Rendering lists into templates/logs and reusing an element format as the top-level letter; upgrading code from join() to String() with formats and misplacing the letters.

Related errors


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