puppetlabs/puppet · error · Puppet::Error

Failed to convert '%{path}' to URI: %{detail}

Error message

Failed to convert '%{path}' to URI: %{detail}

What it means

Puppet::Util.path_to_uri converts a filesystem path into a file: URI: on Windows it rewrites backslashes and extracts a UNC host, then uri_encode escapes components, then splits on '?' and '#', and finally calls URI::Generic.build(params). Any exception from the build (typically URI::InvalidComponentError) is rescued and re-raised as Puppet::Error with the original path and detail (and backtrace) preserved. It is used by file resources' source handling and by metatype when recording resource locations.

Source

Thrown at lib/puppet/util.rb:308

      if unc
        params[:host] = unc[1]
        path = unc[2]
      elsif path =~ %r{^[a-z]:/}i
        path = '/' + path
      end
    end

    # have to split *after* any relevant escaping
    params[:path], params[:query] = uri_encode(path).split('?')
    search_for_fragment = params[:query] ? :query : :path
    if params[search_for_fragment].include?('#')
      params[search_for_fragment], _, params[:fragment] = params[search_for_fragment].rpartition('#')
    end

    begin
      URI::Generic.build(params)
    rescue => detail
      raise Puppet::Error, _("Failed to convert '%{path}' to URI: %{detail}") % { path: path, detail: detail }, detail.backtrace
    end
  end
  module_function :path_to_uri

  # Get the path component of a URI
  def uri_to_path(uri)
    return unless uri.is_a?(URI)

    # CGI.unescape doesn't handle space rules properly in uri paths
    # URI.unescape does, but returns strings in their original encoding
    path = uri_unescape(uri.path.encode(Encoding::UTF_8))

    if Puppet::Util::Platform.windows? && uri.scheme == 'file'
      if uri.host && !uri.host.empty?
        path = "//#{uri.host}" + path # UNC
      else
        path.sub!(%r{^/}, '')
      end

View on GitHub (pinned to e227c27540)

Solutions

  1. Rename the offending file/path to avoid URI-reserved characters (#, ?, [, backslash)
  2. Escape the path before conversion: URI::DEFAULT_PARSER.escape(path) — or pass a cleaner source
  3. If you control the Ruby call site, rescue Puppet::Error and inspect e.cause/original detail to find the bad component

Example fix

# before
uri = Puppet::Util.path_to_uri('/srv/files/report#2?v=3.pdf')

# after
uri = Puppet::Util.path_to_uri('/srv/files/report_2_v3.pdf')
Defensive patterns

Strategy: try-catch

Validate before calling

begin
  URI::Generic.build(scheme: 'file', path: URI::DEFAULT_PARSER.escape(path))
rescue URI::Error
  puts 'not convertible; sanitize the path first'
end

Try / catch

begin
  uri = Puppet::Util.path_to_uri(path)
rescue Puppet::Error => e
  # e.message contains the original detail; fall back to raw path handling
  warn "path not URI-convertible: #{e.message}"
  uri = nil
end

Prevention

When it happens

Trigger: A path containing characters that uri_encode does not escape but URI::Generic.build rejects in a component (e.g. invalid host characters from a Windows UNC match, a malformed percent-escape, or reserved characters landing in the fragment/query split); calling Puppet::Util.path_to_uri directly with a malformed string; file sources with '#' or '?' mid-filename being split into fragment/query and reassembled invalidly.

Common situations: Files with '#', '?', or brackets in their names managed via a file source; Windows UNC paths with characters illegal in a URI host; deep integration code calling path_to_uri on user-supplied strings without sanitization.

Related errors


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