puppetlabs/puppet · error · ArgumentError

Unsupported facts format

Error message

Unsupported facts format

What it means

convert_wire_facts in the catalog compiler only understands two wire formats for client-submitted facts: 'pson' (legacy, still accepted from older agents) and 'application/json' (the current agent format; the payload is URI-unescaped then parsed). Any other value for request.options[:facts_format] raises ArgumentError.

Source

Thrown at lib/puppet/indirector/catalog/compiler.rb:128

    false
  end

  private

  # @param facts [String] facts in a wire format for decoding
  # @param format [String] a content-type string
  # @return [Puppet::Node::Facts] facts object deserialized from supplied string
  # @api private
  def convert_wire_facts(facts, format)
    case format
    when 'pson'
      # We unescape here because the corresponding code in Puppet::Configurer::FactHandler encodes with Puppet::Util.uri_query_encode
      # PSON is deprecated, but continue to accept from older agents
      Puppet::Node::Facts.convert_from('pson', CGI.unescape(facts))
    when 'application/json'
      Puppet::Node::Facts.convert_from('json', CGI.unescape(facts))
    else
      raise ArgumentError, _("Unsupported facts format")
    end
  end

  # Add any extra data necessary to the node.
  def add_node_data(node)
    # Merge in our server-side facts, so they can be used during compilation.
    node.add_server_facts(@server_facts)
  end

  # Determine which checksum to use; if agent_checksum_type is not nil,
  # use the first entry in it that is also in known_checksum_types.
  # If no match is found, return nil.
  def common_checksum_type(agent_checksum_type)
    if agent_checksum_type
      agent_checksum_types = agent_checksum_type.split('.').map(&:to_sym)
      checksum_type = agent_checksum_types.drop_while do |type|
        !known_checksum_types.include? type
      end.first

View on GitHub (pinned to e227c27540)

Solutions

  1. Use exactly 'application/json' (modern) or 'pson' (legacy interop) as the facts_format value
  2. Strip charset/parameters from content types before putting them into options
  3. Send no facts at all if the compile does not depend on them

Example fix

# before (ruby)
opts = { facts: facts_json, facts_format: 'json' }  # => ArgumentError

# after
opts = { facts: facts_json, facts_format: 'application/json' }
Defensive patterns

Strategy: validation

Validate before calling

# ruby
ALLOWED = %w[pson application/json].freeze
fmt = fmt.split(';').first.to_s.strip.downcase
raise ArgumentError, "unsupported facts format #{fmt}" unless ALLOWED.include?(fmt)
opts[:facts_format] = fmt

Type guard

def supported_facts_format?(f)
  %w[pson application/json].include?(f)
end

Try / catch

begin
  Puppet::Resource::Catalog.indirection.find(key, opts)
rescue ArgumentError => e
  raise unless e.message.include?('facts format')
  opts[:facts_format] = 'application/json'
  retry
end

Prevention

When it happens

Trigger: Passing facts_format: 'json' (bare subtype), 'yaml', or a content type with parameters like 'application/json; charset=utf-8' — the value is matched literally against the two accepted strings.

Common situations: Custom clients abbreviating the MIME type to 'json'; tooling copied from the v3 REST API that used format extensions like .pson or .yaml; content-type strings copied straight from HTTP headers.

Related errors


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