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_metadata indirection performs the metadata lookup (HEAD/GET) for a file source against the fileserver API. A 404 normally yields nil, but with options[:fail_on_404] - which Puppet's compiler sets when resolving file resource sources - it raises Puppet::Error with the elided URI and the server's message, e.g. 'Find /puppet/v3/file_metadata/... resulted in 404 with the message: Not Found: ...'. This is the classic error behind 'Error: Could not retrieve file metadata' during agent runs.
Source
Thrown at lib/puppet/indirector/file_metadata/rest.rb:29
url = URI.parse(Puppet::Util.uri_encode(request.uri))
session = Puppet.lookup(:http_session)
api = session.route_to(:fileserver, url: url)
_, file_metadata = api.get_file_metadata(
path: Puppet::Util.uri_unescape(url.path),
environment: request.environment.to_s,
links: request.options[:links],
checksum_type: request.options[:checksum_type],
source_permissions: request.options[:source_permissions]
)
file_metadata
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 search(request)
url = URI.parse(Puppet::Util.uri_encode(request.uri))
session = Puppet.lookup(:http_session)
api = session.route_to(:fileserver, url: url)
_, file_metadatas = api.get_file_metadatas(
path: Puppet::Util.uri_unescape(url.path),
environment: request.environment.to_s,
recurse: request.options[:recurse],
recurselimit: request.options[:recurselimit],
max_files: request.options[:max_files],
ignore: request.options[:ignore],
links: request.options[:links],View on GitHub (pinned to e227c27540)
Solutions
- Verify the file exists in the node's environment: environments/<env>/modules/<mod>/files/<path> on the server.
- Check the node's environment (puppet config print environment) and the module's presence in that environment.
- Fix spelling, case, and the puppet:///modules/<mod>/ prefix mapping (it addresses the module's files/ directory).
- In direct API use, omit fail_on_404 and handle a nil result yourself when absence is expected.
Example fix
# before meta = Puppet::FileServing::Metadata.indirection.find( 'puppet:///modules/app/etc/app.conf', fail_on_404: true) # raises for a missing file # after: treat absence explicitly meta = Puppet::FileServing::Metadata.indirection.find( 'puppet:///modules/app/etc/app.conf') return if meta.nil?
Defensive patterns
Strategy: try-catch
Validate before calling
meta = Puppet::FileServing::Metadata.indirection.find(uri) return if meta.nil? # 404 surfaces as nil when fail_on_404 is unset fail 'source missing: ' + uri if ENV['STRICT_SOURCES']
Try / catch
begin
meta = Puppet::FileServing::Metadata.indirection.find(uri, fail_on_404: true)
rescue Puppet::Error => e
raise unless e.message.include?('404')
fail 'file source missing: ' + uri.to_s
end Prevention
- Resolve every file source during CI catalog compilation.
- Keep module files and manifests in the same change/PR.
- Omit fail_on_404 and handle nil when absence is a normal state.
When it happens
Trigger: Compiling/applying a catalog with source 'puppet:///modules/mod/missing' while fail_on_404 is set; requesting metadata for a file that exists in a different environment; Ruby calls to Puppet::FileServing::Metadata.indirection.find(..., fail_on_404: true).
Common situations: Deleted or renamed module files still referenced by manifests; branch-only files not merged to the node's environment; new nodes pinned to an environment lacking the module; fileserver mount path changes after server upgrades.
Related errors
- Find %{uri} resulted in 404 with the message: %{body}
- Invalid entry at %{error_location}: '%{file_text}'
- %{mount} is already mounted at %{name} at %{error_location}
- Invalid mount name format '%{name}'
- Mounts without paths are not usable
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/b81594a7cd817826.
Report an issue: GitHub.