puppetlabs/puppet · error · Puppet::Network::FormatHandler::FormatError

Failed to serialize %{model} for '%{key}': %{detail}

Error message

Failed to serialize %{model} for '%{key}': %{detail}

What it means

When building a response, the handler tries each format accepted by the client and serializes the model; if serialization raises Puppet::Network::FormatHandler::FormatError, the detail is appended to this message. Behavior then depends on allow_pson_serialization (default false): when true, Puppet logs a warning and tries the next accepted format; when false, the FormatError is re-raised and surfaces as a server-side error. The classic cause is data the chosen format cannot represent, most often rich data asked for as PSON.

Source

Thrown at lib/puppet/network/http/api/indirected_routes.rb:195

    result = indirection.save(sent_object, key)

    response.respond_with(200, formatter, formatter.render(result))
  end

  # Return the first response formatter that didn't cause the yielded
  # block to raise a FormatError.
  def first_response_formatter_for(model, request, key, &block)
    formats = accepted_response_formatters_for(model, request)
    formatter = formats.find do |format|
      yield format
      true
    rescue Puppet::Network::FormatHandler::FormatError => err
      msg = _("Failed to serialize %{model} for '%{key}': %{detail}") %
            { model: model, key: key, detail: err }
      if Puppet[:allow_pson_serialization]
        Puppet.warning(msg)
      else
        raise Puppet::Network::FormatHandler::FormatError, msg
      end
      false
    end

    return formatter if formatter

    raise Puppet::Network::HTTP::Error::HTTPNotAcceptableError.new(
      _("No supported formats are acceptable (Accept: %{accepted_formats})") % { accepted_formats: formats.map(&:mime).join(', ') },
      Puppet::Network::HTTP::Issues::UNSUPPORTED_FORMAT
    )
  end

  # Return an array of response formatters that the client accepts and
  # the server supports.
  def accepted_response_formatters_for(model_class, request)
    request.response_formatters_for(model_class.supported_formats)
  end

View on GitHub (pinned to e227c27540)

Solutions

  1. Make clients request a format that can carry the data, e.g. Accept: application/json
  2. Upgrade agents so they no longer depend on PSON serialization
  3. If legacy PSON clients must keep working, set allow_pson_serialization = true in puppet.conf (downgrades the failure to a warning and falls through to other formats)
  4. Read the %{detail} portion of the message to identify exactly which value failed to serialize

Example fix

# before
curl -H 'Accept: pson' "https://puppet:8140/puppet/v3/catalog/mynode?environment=production"

# after
curl -H 'Accept: application/json' "https://puppet:8140/puppet/v3/catalog/mynode?environment=production"
Defensive patterns

Strategy: try-catch

Try / catch

begin
  response = http.get("/puppet/v3/catalog/#{certname}",
                      params: { environment: env },
                      headers: { 'Accept' => 'application/json' })
rescue Puppet::Network::FormatHandler::FormatError => e
  # e.message includes the %{detail} naming the unserializable value
  Puppet.err("catalog serialization failed for #{certname}: #{e.message}")
  raise
end

Prevention

When it happens

Trigger: A catalog or facts response containing rich data (Sensitive values, Puppet data types, versioned data) requested with Accept: pson, while Puppet[:allow_pson_serialization] = false turns the fallback warning into a hard failure. The %{detail} names the value that failed to serialize.

Common situations: Mixed-version infrastructure where old agents request PSON from newer masters; modules that put rich data into catalogs; sites that rely on the default allow_pson_serialization=false hardening while still serving legacy PSON clients.

Related errors


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