puppetlabs/puppet · error · Puppet::Error

Catalog for %{request} was requested with fact definition fo

Error message

Catalog for %{request} was requested with fact definition for the wrong node (%{fact_name}).

What it means

After deserializing the facts sent with a catalog request, the compiler verifies facts.name equals request.key (the node whose catalog was requested). A mismatch raises Puppet::Error because compiling a node's catalog against another node's facts would produce a silently wrong catalog (hostname/IP-dependent resources would be wrong).

Source

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

  # @param request [Puppet::Indirector::Request] an indirection request
  #   (possibly) containing facts
  # @return [Puppet::Node::Facts] facts object corresponding to facts in request
  def extract_facts_from_request(request)
    text_facts = request.options[:facts]
    return unless text_facts

    format = request.options[:facts_format]
    unless format
      raise ArgumentError, _("Facts but no fact format provided for %{request}") % { request: request.key }
    end

    Puppet::Util::Profiler.profile(_("Found facts"), [:compiler, :find_facts]) do
      facts = text_facts.is_a?(Puppet::Node::Facts) ? text_facts :
                                                      convert_wire_facts(text_facts, format)

      unless facts.name == request.key
        raise Puppet::Error, _("Catalog for %{request} was requested with fact definition for the wrong node (%{fact_name}).") % { request: request.key.inspect, fact_name: facts.name.inspect }
      end

      return facts
    end
  end

  def save_facts_from_request(facts, request)
    Puppet::Node::Facts.indirection.save(facts, nil,
                                         :environment => request.environment,
                                         :transaction_uuid => request.options[:transaction_uuid])
  end

  # Compile a node's catalog.
  def find(request)
    facts = extract_facts_from_request(request)

    save_facts_from_request(facts, request) unless facts.nil?

View on GitHub (pinned to e227c27540)

Solutions

  1. Make the facts name match the request: set facts.name = request.key (or fix the certname fact) before serializing
  2. Generate per-node facts fixtures in tests instead of sharing one
  3. On agents, clear stale fact caches and stop custom facts from shadowing certname

Example fix

# before (ruby)
facts = Puppet::Node::Facts.new('nodeB', values)
Puppet::Resource::Catalog.indirection.find('nodeA',
  facts: facts.to_pson, facts_format: 'pson')  # => Puppet::Error: wrong node

# after
facts.name = 'nodeA'
Puppet::Resource::Catalog.indirection.find('nodeA',
  facts: facts.to_pson, facts_format: 'pson')
Defensive patterns

Strategy: validation

Validate before calling

# ruby
facts.name = request_key if facts.respond_to?(:name=)
raise ArgumentError, 'facts belong to another node' unless facts.name == request_key

Type guard

def facts_match_node?(facts, key)
  facts.nil? || facts.name == key
end

Try / catch

begin
  Puppet::Resource::Catalog.indirection.find(key, opts)
rescue Puppet::Error => e
  raise unless e.message.include?('wrong node')
  facts.name = key
  opts[:facts] = facts.to_pson
  retry
end

Prevention

When it happens

Trigger: Requesting a catalog for nodeA with a facts payload whose name field is nodeB — e.g. find('nodeA', facts: facts_for_nodeB_serialized, facts_format: 'pson'); a facts object reused across nodes in a test harness.

Common situations: certname in puppet.conf set to one FQDN while a custom fact or stale fact cache reports a different hostname; monitoring or compile-testing tools that fetch facts once and request catalogs for many nodes; facts from a golden image reporting the image's original hostname.

Related errors


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