puppetlabs/puppet · error · Puppet::Error

Find %{uri} resulted in 404 with the message: %{body}

Error message

Find %{uri} resulted in 404 with the message: %{body}

What it means

The facts REST terminus maps a server 404 on a facts GET to nil (fact set not found) unless the request carried options[:fail_on_404], in which case it raises Puppet::Error embedding the request path and the server's response body. Same contract as the catalog REST terminus: find returns nil for missing data unless the caller explicitly demands failure.

Source

Thrown at lib/puppet/indirector/facts/rest.rb:23

class Puppet::Node::Facts::Rest < Puppet::Indirector::REST
  desc "Find and save facts about nodes over HTTP via REST."

  def find(request)
    session = Puppet.lookup(:http_session)
    api = session.route_to(:puppet)
    _, facts = api.get_facts(
      request.key,
      environment: request.environment.to_s
    )
    facts
  rescue Puppet::HTTP::ResponseError => e
    if e.response.code == 404
      return nil unless request.options[:fail_on_404]

      _, body = parse_response(e.response)
      msg = _("Find %{uri} resulted in 404 with the message: %{body}") % { uri: elide(e.response.url.path, 100), body: body }
      raise Puppet::Error, msg
    else
      raise convert_to_http_error(e.response)
    end
  end

  def save(request)
    raise ArgumentError, _("PUT does not accept options") unless request.options.empty?

    session = Puppet.lookup(:http_session)
    api = session.route_to(:puppet)
    api.put_facts(
      request.key,
      facts: request.instance,
      environment: request.environment.to_s
    )

    # preserve existing behavior
    nil

View on GitHub (pinned to e227c27540)

Solutions

  1. Drop fail_on_404 and treat nil as 'no facts on this server' for discovery or inventory use cases
  2. If facts should exist, verify server-side (puppet facts find or a PuppetDB query) and re-submit by running the agent on the node
  3. Check the response body in the message — it distinguishes unknown-node 404s from unknown-route 404s

Example fix

# before (ruby)
facts = Puppet::Node::Facts.indirection.find(name,
  fail_on_404: true)  # 404 => Puppet::Error

# after
facts = Puppet::Node::Facts.indirection.find(name)  # 404 => nil
puts 'no facts stored' unless facts
Defensive patterns

Strategy: try-catch

Validate before calling

# ruby
facts = Puppet::Node::Facts.indirection.find(name)  # default nil semantics
return :no_facts if facts.nil?

Type guard

def facts_stored?(name)
  !Puppet::Node::Facts.indirection.find(name).nil?
end

Try / catch

begin
  Puppet::Node::Facts.indirection.find(name, fail_on_404: true)
rescue Puppet::Error => e
  raise unless e.message.include?('404')
  nil  # treat as absent and report
end

Prevention

When it happens

Trigger: Puppet::Node::Facts.indirection.find(name, fail_on_404: true) against a server that answers 404 — facts were never stored, were cleaned, or the request hit a server without that node's facts.

Common situations: Inventory scripts probing facts for decommissioned or never-registered nodes; facts cleaned on the master or purged from PuppetDB; a load balancer routing the GET to a server whose fact store does not contain the node.

Related errors


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