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 REST terminus for the file_content indirection wraps HTTP 404 from the Puppet fileserver API. By default 404 returns nil (treated as file absent); when the request carries options[:fail_on_404], which Puppet sets when resolving file sources during catalog application, it raises Puppet::Error embedding the elided URI path and the server's parsed message body so the missing source is reported loudly instead of silently yielding nil.

Source

Thrown at lib/puppet/indirector/file_content/rest.rb:32

    url = URI.parse(Puppet::Util.uri_encode(request.uri))
    session = Puppet.lookup(:http_session)
    api = session.route_to(:fileserver, url: url)

    api.get_file_content(
      path: Puppet::Util.uri_unescape(url.path),
      environment: request.environment.to_s
    ) do |data|
      content << data
    end

    Puppet::FileServing::Content.from_binary(content.string)
  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
end

View on GitHub (pinned to e227c27540)

Solutions

  1. Verify the file exists server-side: puppet:///modules/mod/path maps to environments/<env>/modules/mod/files/path on the Puppet server.
  2. Confirm the node's environment matches the environment that contains the file.
  3. Re-check spelling and case of the source URI and module name.
  4. If absence is legitimate and you call the API directly, omit fail_on_404 so the lookup returns nil instead of raising.

Example fix

# manifest - before
file { '/etc/app/app.conf':
  source => 'puppet:///modules/app/etc/app.con', # typo
}

# after
file { '/etc/app/app.conf':
  source => 'puppet:///modules/app/etc/app.conf',
}
Defensive patterns

Strategy: fallback

Validate before calling

# do not opt into failing on absence unless absence is fatal
content = Puppet::FileServing::Content.indirection.find(uri) # returns nil on 404
if content.nil?
  content = Puppet::FileServing::Content.from_binary(File.binread('/etc/app.conf.default'))
end

Try / catch

begin
  content = Puppet::FileServing::Content.indirection.find(uri, fail_on_404: true)
rescue Puppet::Error => e
  Puppet.warning(uri + ' unavailable, using default')
  content = Puppet::FileServing::Content.from_binary(DEFAULT)
end

Prevention

When it happens

Trigger: A file resource with source 'puppet:///modules/<mod>/<path>' where the file does not exist on the server in the node's environment; wrong module name or mount; Ruby calls to Puppet::FileServing::Content.indirection.find(uri, fail_on_404: true) for a missing file.

Common situations: Files deleted from a module but still referenced by manifests; environments out of sync (file merged to production while the agent runs a feature branch); case mismatches in paths on case-sensitive servers; fileserver mount renamed.

Related errors


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