jnunemaker/httparty · error · ArgumentError

uri must be a #{uri_adapter}, not a #{uri.class}

Error message

uri must be a #{uri_adapter}, not a #{uri.class}

What it means

ConnectionAdapter's constructor raises ArgumentError when the uri argument is not an instance of the configured uri_adapter class (options[:uri_adapter], defaulting to URI). HTTParty parses request paths with the same adapter, so in the normal request flow the types line up; this error appears when a custom connection_adapter builds its own adapter or someone instantiates HTTParty::ConnectionAdapter directly and passes, say, an Addressable::URI while the adapter default is URI (or the reverse).

Source

Thrown at lib/httparty/connection_adapter.rb:93

      verify_peer: true
    }

    # Public
    def self.call(uri, options)
      new(uri, options).connection
    end

    def self.default_cert_store
      @default_cert_store ||= OpenSSL::X509::Store.new.tap do |cert_store|
        cert_store.set_default_paths
      end
    end

    attr_reader :uri, :options

    def initialize(uri, options = {})
      uri_adapter = options[:uri_adapter] || URI
      raise ArgumentError, "uri must be a #{uri_adapter}, not a #{uri.class}" unless uri.is_a? uri_adapter

      @uri = uri
      @options = OPTION_DEFAULTS.merge(options)
    end

    def connection
      host = clean_host(uri.host)
      port = uri.port || (uri.scheme == 'https' ? 443 : 80)
      if options.key?(:http_proxyaddr)
        http = Net::HTTP.new(
          host,
          port,
          options[:http_proxyaddr],
          options[:http_proxyport],
          options[:http_proxyuser],
          options[:http_proxypass]
        )
      else

View on GitHub (pinned to 8f4a09e343)

Solutions

  1. Pass the same URI class the request was parsed with: use options[:uri_adapter] when building the adapter.
  2. Re-parse before constructing: `HTTParty::ConnectionAdapter.new(uri_adapter.parse(uri.to_s), uri_adapter: uri_adapter)`.
  3. Standardize the whole client on one adapter by setting `uri_adapter Addressable::URI` (or default URI) at the class level.

Example fix

# before
adapter = HTTParty::ConnectionAdapter.new(
  Addressable::URI.parse('http://example.com/'),
  {}
)  # default uri_adapter is URI -> ArgumentError

# after
adapter = HTTParty::ConnectionAdapter.new(
  Addressable::URI.parse('http://example.com/'),
  uri_adapter: Addressable::URI
)
Defensive patterns

Strategy: validation

Validate before calling

adapter_class = options[:uri_adapter] || URI
uri = adapter_class.parse(uri.to_s) unless uri.is_a?(adapter_class)
HTTParty::ConnectionAdapter.new(uri, options)

Type guard

matches_adapter = ->(uri, adapter = URI) { uri.is_a?(adapter) }

Try / catch

begin
  HTTParty::ConnectionAdapter.new(uri, options)
rescue ArgumentError => e
  raise if options[:uri_adapter]
  HTTParty::ConnectionAdapter.new(URI.parse(uri.to_s), options)
end

Prevention

When it happens

Trigger: `HTTParty::ConnectionAdapter.new(Addressable::URI.parse('http://x/'), {})` (default adapter is URI); a custom connection_adapter proc that re-wraps options with a different uri_adapter than the one used to parse the path; passing URI::HTTPS when uri_adapter Addressable::URI is configured.

Common situations: Writing custom connection adapters for instrumentation or connection pooling, mixing URI and Addressable handling across code paths after adopting uri_adapter, and test harnesses that construct the adapter directly with the wrong URI class.

Related errors


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