puppetlabs/puppet · error · ArgumentError

Could not understand URL %{key}: %{detail}

Error message

Could not understand URL %{key}: %{detail}

What it means

When a request key is a URI, Request#set_uri_key runs URI.parse(Puppet::Util.uri_encode(key)); any failure raises ArgumentError with the key and detail. This happens for keys that look like URLs but violate RFC 3986 after encoding: embedded spaces or brackets that survive encoding, 'host:' with no scheme text, control characters, or unescaped percent sequences like '%' alone (bad %-encoding).

Source

Thrown at lib/puppet/indirector/request.rb:168

  private

  def set_attributes(options)
    OPTION_ATTRIBUTES.each do |attribute|
      if options.include?(attribute.to_sym)
        send(attribute.to_s + "=", options[attribute])
        options.delete(attribute)
      end
    end
  end

  # Parse the key as a URI, setting attributes appropriately.
  def set_uri_key(key)
    @uri = key
    begin
      # calling uri_encode for UTF-8 characters will % escape them and keep them UTF-8
      uri = URI.parse(Puppet::Util.uri_encode(key))
    rescue => detail
      raise ArgumentError, _("Could not understand URL %{key}: %{detail}") % { key: key, detail: detail }, detail.backtrace
    end

    # Just short-circuit these to full paths
    if uri.scheme == "file"
      @key = Puppet::Util.uri_to_path(uri)
      return
    end

    @server = uri.host if uri.host && !uri.host.empty?

    # If the URI class can look up the scheme, it will provide a port,
    # otherwise it will default to '0'.
    if uri.port.to_i == 0 and uri.scheme == "puppet"
      @port = Puppet.settings[:serverport].to_i
    else
      @port = uri.port.to_i
    end

View on GitHub (pinned to e227c27540)

Solutions

  1. Inspect the exact key in the message and fix the bad characters (unescaped %, spaces, brackets)
  2. Build keys with URI and escape components separately: URI::Generic.build(...) or ERB::Util.url_encode on path segments
  3. Use Puppet::Util.uri_encode on the raw string before it becomes a key, rather than hand-concatenating
  4. For local paths, prefer plain filesystem paths (file scheme is short-circuited to a path) and avoid embedding them in pseudo-URLs

Example fix

# before
key = "puppet:///files/my file.txt".sub('files', 'files')  # raw space survives
URI.parse(key)  # => ArgumentError: Could not understand URL ...

# after
require 'erb'
key = "puppet:///files/#{ERB::Util.url_encode('my file.txt')}"  # my%20file.txt
Defensive patterns

Strategy: validation

Validate before calling

begin
  URI.parse(Puppet::Util.uri_encode(key))
rescue URI::Error, ArgumentError => e
  raise ArgumentError, "refusing to build request with unparseable key #{key.inspect}: #{e.message}"
end

Try / catch

begin
  request = Puppet::Indirection::Request.new(indirection, method, key, nil)
rescue ArgumentError => e
  raise unless e.message =~ /Could not understand URL/
  key = ERB::Util.url_encode(key)  # normalize and retry once
  request = Puppet::Indirection::Request.new(indirection, method, key, nil)
end

Prevention

When it happens

Trigger: Passing keys such as 'puppet://server:8140/production/%%' (bad percent escape), 'file:///tmp/my file.yaml' handled wrongly, or resource keys with raw spaces/control characters to indirector APIs that treat keys as URIs (puppet filebucket, file_content/file_metadata REST keys, catalog with URI-style node keys).

Common situations: Shell quoting mistakes that inject spaces into resource references; user-supplied paths used as indirection keys without escaping; filebucket or fileserver URIs built by string concatenation instead of URI libraries.

Related errors


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