{"record":{"id":"1dc2a639798ac11a","repo":"puppetlabs/puppet","slug":"catalog-for-request-was-requested-with-fact-def","errorCode":null,"errorMessage":"Catalog for %{request} was requested with fact definition for the wrong node (%{fact_name}).","messagePattern":"Catalog for %(.+?) was requested with fact definition for the wrong node \\(%(.+?)\\)\\.","errorType":"exception","errorClass":"Puppet::Error","httpStatus":null,"severity":"error","filePath":"lib/puppet/indirector/catalog/compiler.rb","lineNumber":38,"sourceCode":"\n  # @param request [Puppet::Indirector::Request] an indirection request\n  #   (possibly) containing facts\n  # @return [Puppet::Node::Facts] facts object corresponding to facts in request\n  def extract_facts_from_request(request)\n    text_facts = request.options[:facts]\n    return unless text_facts\n\n    format = request.options[:facts_format]\n    unless format\n      raise ArgumentError, _(\"Facts but no fact format provided for %{request}\") % { request: request.key }\n    end\n\n    Puppet::Util::Profiler.profile(_(\"Found facts\"), [:compiler, :find_facts]) do\n      facts = text_facts.is_a?(Puppet::Node::Facts) ? text_facts :\n                                                      convert_wire_facts(text_facts, format)\n\n      unless facts.name == request.key\n        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 }\n      end\n\n      return facts\n    end\n  end\n\n  def save_facts_from_request(facts, request)\n    Puppet::Node::Facts.indirection.save(facts, nil,\n                                         :environment => request.environment,\n                                         :transaction_uuid => request.options[:transaction_uuid])\n  end\n\n  # Compile a node's catalog.\n  def find(request)\n    facts = extract_facts_from_request(request)\n\n    save_facts_from_request(facts, request) unless facts.nil?\n","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/indirector/catalog/compiler.rb#L20-L56","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","solutions":["Make the facts name match the request: set facts.name = request.key (or fix the certname fact) before serializing","Generate per-node facts fixtures in tests instead of sharing one","On agents, clear stale fact caches and stop custom facts from shadowing certname"],"exampleFix":"# before (ruby)\nfacts = Puppet::Node::Facts.new('nodeB', values)\nPuppet::Resource::Catalog.indirection.find('nodeA',\n  facts: facts.to_pson, facts_format: 'pson')  # => Puppet::Error: wrong node\n\n# after\nfacts.name = 'nodeA'\nPuppet::Resource::Catalog.indirection.find('nodeA',\n  facts: facts.to_pson, facts_format: 'pson')","handlingStrategy":"validation","validationCode":"# ruby\nfacts.name = request_key if facts.respond_to?(:name=)\nraise ArgumentError, 'facts belong to another node' unless facts.name == request_key","typeGuard":"def facts_match_node?(facts, key)\n  facts.nil? || facts.name == key\nend","tryCatchPattern":"begin\n  Puppet::Resource::Catalog.indirection.find(key, opts)\nrescue Puppet::Error => e\n  raise unless e.message.include?('wrong node')\n  facts.name = key\n  opts[:facts] = facts.to_pson\n  retry\nend","preventionTips":["Set the facts object name to the request key before serializing, every time","Never share facts fixtures across nodes in tests; generate them per certname","Keep custom facts from overwriting certname on agents"],"tags":["puppet-compiler","facts","node-identity","catalog"],"backgroundTag":"node-identity-mismatch","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}