bblimke/webmock · error · ArgumentError

URI should be a String, Regexp, Addressable::Template, a cal

Error message

URI should be a String, Regexp, Addressable::Template, a callable object, or respond to #to_str. Got: #{uri.class}

What it means

The URI argument to stub_request/a_request must be a String, Regexp, Addressable::Template, a callable object, a stdlib URI::Generic (URI::HTTP and URI::HTTPS inherit from it), or anything responding to #to_str. create_uri_pattern (lib/webmock/request_pattern.rb:80) dispatches on exactly those types and raises ArgumentError naming the class it actually got otherwise. The classic offender is Addressable::URI: it is a webmock dependency and apps parse URLs with it, but it responds to #to_s rather than #to_str, so stub_request(:get, Addressable::URI.parse(url)) raises.

Source

Thrown at lib/webmock/request_pattern.rb:92

    def validate_basic_auth!(basic_auth)
      if !basic_auth.is_a?(Array) || basic_auth.map{|e| e.is_a?(String)}.uniq != [true]
        raise "The basic_auth option value should be an array which contains 2 strings: username and password"
      end
    end

    def create_uri_pattern(uri)
      if uri.is_a?(Regexp)
        URIRegexpPattern.new(uri)
      elsif uri.is_a?(Addressable::Template)
        URIAddressablePattern.new(uri)
      elsif uri.respond_to?(:call)
        URICallablePattern.new(uri)
      elsif uri.is_a?(::URI::Generic)
        URIStringPattern.new(uri.to_s)
      elsif uri.respond_to?(:to_str)
        URIStringPattern.new(uri.to_str)
      else
        raise ArgumentError.new("URI should be a String, Regexp, Addressable::Template, a callable object, or respond to #to_str. Got: #{uri.class}")
      end
    end
  end


  class MethodPattern
    def initialize(pattern)
      @pattern = pattern
    end

    def matches?(method)
      @pattern == method || @pattern == :any
    end

    def to_s
      @pattern.to_s
    end
  end

View on GitHub (pinned to b187df8827)

Solutions

  1. Convert before stubbing: stub_request(:get, uri.to_s) - works for Addressable::URI and URI::HTTP alike
  2. For pattern matching use Addressable::Template.new('https://api.example.com/v1/{id}') which is supported natively, or a Regexp like %r{api\.example\.com/v1}
  3. If the value is nil, fix the source: check the ENV or config read that produced it - the error names the class you passed
  4. For dynamic matching pass a lambda: stub_request(:get, ->(uri) { uri.host == 'api.example.com' })

Example fix

# before
stub_request(:get, Addressable::URI.parse('https://api.example.com/v1/users'))  # ArgumentError: Got: Addressable::URI

# after
stub_request(:get, 'https://api.example.com/v1/users')
Defensive patterns

Strategy: type-guard

Validate before calling

parsed = begin
  Addressable::URI.parse(raw)
rescue Addressable::URI::InvalidURIError
  raw
end
stub_request(:get, parsed.is_a?(Addressable::URI) ? parsed.to_s : parsed)

Type guard

def stubbable_uri?(u)
  u.is_a?(String) || u.is_a?(Regexp) || u.is_a?(Addressable::Template) ||
    u.respond_to?(:call) || u.is_a?(::URI::Generic) || u.respond_to?(:to_str)
end

Prevention

When it happens

Trigger: Passing an Addressable::URI instance. Passing nil (an ENV/config lookup that returned nothing - the error says Got: NilClass). Passing a Hash or Symbol. Passing a custom URL wrapper object that only implements to_s.

Common situations: Apps that normalize or build URLs through Addressable before stubbing; URL helpers that return a String in one branch and a URI object in another; optional endpoints configured via ENV that are unset in CI.

Understand the failure class

Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.

Related errors


AI-assisted analysis of bblimke/webmock@b187df8827 (2026-08-23). Data as JSON: /api/errors/37fb29d3d59782cf. Report an issue: GitHub.