jnunemaker/httparty · error · ArgumentError

bad argument (expected #{uri_adapter} object or URI string)

Error message

bad argument (expected #{uri_adapter} object or URI string)

What it means

Request#path= raises ArgumentError 'bad argument (expected URI object or URI string)' when the path passed to a verb method is neither an instance of the configured uri_adapter nor convertible with String.try_convert. Every HTTParty verb (get/post/put/...) funnels its path through this setter, so passing nil, an Integer, a Symbol, or objects like Pathname that do not define to_str fail here before any connection is opened.

Source

Thrown at lib/httparty/request.rb:87

        default_params: {},
        follow_redirects: true,
        parser: Parser,
        uri_adapter: URI,
        connection_adapter: ConnectionAdapter
      }.merge(o)
      self.path = path
      set_basic_auth_from_uri
    end

    def path=(uri)
      uri_adapter = options[:uri_adapter]

      @path = if uri.is_a?(uri_adapter)
        uri
      elsif String.try_convert(uri)
        uri_adapter.parse(uri).normalize
      else
        raise ArgumentError,
          "bad argument (expected #{uri_adapter} object or URI string)"
      end
    end

    def request_uri(uri)
      if uri.respond_to? :request_uri
        uri.request_uri
      else
        uri.path
      end
    end

    def uri
      if redirect && path.relative? && path.path[0] != '/'
        last_uri_host = @last_uri.path.gsub(/[^\/]+$/, '')

        path.path = "/#{path.path}" if last_uri_host[-1] != '/'
        path.path = "#{last_uri_host}#{path.path}"

View on GitHub (pinned to 8f4a09e343)

Solutions

  1. Coerce to String at the call site: `Foo.get(url.to_s)` or `Foo.get(url&.to_s)`.
  2. Fail fast on nil upstream: `raise ArgumentError, 'url missing' if url.nil?` before building the request.
  3. When passing Addressable objects, configure `uri_adapter Addressable::URI` on the class.

Example fix

# before
url = ENV['ENDPOINT']            # nil when unset
Foo.get(url)                     # ArgumentError: bad argument

# after
url = ENV.fetch('ENDPOINT')
Foo.get(url)
Defensive patterns

Strategy: validation

Validate before calling

url = ENV.fetch('ENDPOINT')
raise ArgumentError, "path must be a String or #{URI}, got #{url.class}" unless url.is_a?(String) || url.is_a?(URI)
Foo.get(url)

Type guard

valid_path = ->(p) { p.is_a?(String) || p.is_a?(URI) }

Try / catch

begin
  Foo.get(path)
rescue ArgumentError => e
  raise unless e.message.include?('bad argument')
  raise ArgumentError, "URL was #{path.inspect} — check the variable feeding this call"
end

Prevention

When it happens

Trigger: `Foo.get(nil)` (usually an interpolated variable that came back nil), `Foo.get(42)`, `Foo.get(:show)`, `Foo.get(Pathname.new('/tmp/url.txt'))`, or `Foo.get(['http://x'])`. Passing an Addressable::URI while uri_adapter is the default URI also lands here.

Common situations: URLs built from ENV vars, DB fields or ERB templates that are nil in some environments, Pathname or URI::Generic objects leaking in from file-handling code, and Addressable objects passed to a client configured with the default URI adapter.

Related errors


AI-assisted analysis of jnunemaker/httparty@8f4a09e343 (2026-08-21). Data as JSON: /api/errors/7f5bd994132f51ab. Report an issue: GitHub.