{"record":{"id":"0926e590efc4a8c8","repo":"puppetlabs/puppet","slug":"could-not-understand-url-key-detail","errorCode":null,"errorMessage":"Could not understand URL %{key}: %{detail}","messagePattern":"Could not understand URL %(.+?): %(.+?)","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/puppet/indirector/request.rb","lineNumber":168,"sourceCode":"  private\n\n  def set_attributes(options)\n    OPTION_ATTRIBUTES.each do |attribute|\n      if options.include?(attribute.to_sym)\n        send(attribute.to_s + \"=\", options[attribute])\n        options.delete(attribute)\n      end\n    end\n  end\n\n  # Parse the key as a URI, setting attributes appropriately.\n  def set_uri_key(key)\n    @uri = key\n    begin\n      # calling uri_encode for UTF-8 characters will % escape them and keep them UTF-8\n      uri = URI.parse(Puppet::Util.uri_encode(key))\n    rescue => detail\n      raise ArgumentError, _(\"Could not understand URL %{key}: %{detail}\") % { key: key, detail: detail }, detail.backtrace\n    end\n\n    # Just short-circuit these to full paths\n    if uri.scheme == \"file\"\n      @key = Puppet::Util.uri_to_path(uri)\n      return\n    end\n\n    @server = uri.host if uri.host && !uri.host.empty?\n\n    # If the URI class can look up the scheme, it will provide a port,\n    # otherwise it will default to '0'.\n    if uri.port.to_i == 0 and uri.scheme == \"puppet\"\n      @port = Puppet.settings[:serverport].to_i\n    else\n      @port = uri.port.to_i\n    end\n","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/indirector/request.rb#L150-L186","documentation":"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).","triggerScenarios":"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).","commonSituations":"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.","solutions":["Inspect the exact key in the message and fix the bad characters (unescaped %, spaces, brackets)","Build keys with URI and escape components separately: URI::Generic.build(...) or ERB::Util.url_encode on path segments","Use Puppet::Util.uri_encode on the raw string before it becomes a key, rather than hand-concatenating","For local paths, prefer plain filesystem paths (file scheme is short-circuited to a path) and avoid embedding them in pseudo-URLs"],"exampleFix":"# before\nkey = \"puppet:///files/my file.txt\".sub('files', 'files')  # raw space survives\nURI.parse(key)  # => ArgumentError: Could not understand URL ...\n\n# after\nrequire 'erb'\nkey = \"puppet:///files/#{ERB::Util.url_encode('my file.txt')}\"  # my%20file.txt","handlingStrategy":"validation","validationCode":"begin\n  URI.parse(Puppet::Util.uri_encode(key))\nrescue URI::Error, ArgumentError => e\n  raise ArgumentError, \"refusing to build request with unparseable key #{key.inspect}: #{e.message}\"\nend","typeGuard":null,"tryCatchPattern":"begin\n  request = Puppet::Indirection::Request.new(indirection, method, key, nil)\nrescue ArgumentError => e\n  raise unless e.message =~ /Could not understand URL/\n  key = ERB::Util.url_encode(key)  # normalize and retry once\n  request = Puppet::Indirection::Request.new(indirection, method, key, nil)\nend","preventionTips":["Percent-encode path components at construction time with ERB::Util.url_encode","Validate user-supplied keys against /\\A[\\w.\\-/:%]+\\z/ before they reach the indirector","Build URIs with URI::Generic.build instead of string concatenation"],"tags":["puppet","indirector","uri","url-encoding","argument-error"],"backgroundTag":"invalid-uri","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}