SeleniumHQ/selenium · error · ArgumentError

:options must be an instance of #

Error message

:options must be an instance of #{default_options.class}

What it means

When starting a local driver, process_options validates that the supplied :options object is an instance of the Options subclass that matches the target browser (e.g. Chrome::Options for Chrome, Firefox::Options for Firefox). If the options object's class does not match, ArgumentError is raised. This prevents silently sending the wrong capability payload to the driver service.

Solutions

  1. Construct the Options class that matches the browser: Selenium::WebDriver::Chrome::Options.new for :chrome.
  2. If you do not need custom options, omit the :options argument so Selenium uses the default Options.send(browser) instance.
  3. Double-check that the symbol passed to Driver.for matches the Options subclass you instantiated.

Example fix

# before
options = Selenium::WebDriver::Firefox::Options.new
driver = Selenium::WebDriver.for(:chrome, options: options)

# after
options = Selenium::WebDriver::Chrome::Options.new
driver = Selenium::WebDriver.for(:chrome, options: options)
Defensive patterns

Strategy: type-guard

Validate before calling

expected = Selenium::WebDriver::Options.send(browser).class
raise ArgumentError, "options must be #{expected}" unless options.is_a?(expected)

Type guard

def options_match_browser?(options, browser)
  options.is_a?(Selenium::WebDriver::Options.send(browser).class)
end

Try / catch

begin
  Selenium::WebDriver.for(browser, options: options)
rescue ArgumentError => e
  raise unless e.message.include?('must be an instance of')
  options = Selenium::WebDriver::Options.send(browser)
  Selenium::WebDriver.for(browser, options: options)
end

Prevention

When it happens

Trigger: Passing Selenium::WebDriver::Firefox::Options.new as :options to Selenium::WebDriver.for(:chrome, options:). Passing a plain Hash or a remote Capabilities object instead of an Options instance. Mixing Edge::Options with a Chrome driver.

Common situations: Copy-pasting an Options setup block from another browser and changing only the :browser symbol. Switching the browser without updating the Options class. Passing an Options object whose class is a parent or unrelated type.

Related errors


AI-assisted analysis of SeleniumHQ/selenium@aa36b38e69 (2026-08-14). Data as JSON: /api/errors/76f2cf4283748969. Report an issue: GitHub.

Appendix: source

Thrown at rb/lib/selenium/webdriver/common/local_driver.rb:49

        begin
          yield(caps, http_client) if block_given?
        rescue Selenium::WebDriver::Error::WebDriverError
          @service_manager&.stop
          raise
        end
      end

      def service_url(service)
        @service_manager = service.launch
        @service_manager.uri
      end

      def process_options(options, service)
        default_options = Options.send(browser)
        options ||= default_options

        unless options.is_a?(default_options.class)
          raise ArgumentError, ":options must be an instance of #{default_options.class}"
        end

        finder = WebDriver::DriverFinder.new(options, service)
        options.binary = finder.browser_path if options.respond_to?(:binary) && finder.browser_path?
        service.executable_path = finder.driver_path
        options.browser_version = nil if options.respond_to?(:binary) && options.binary
        options.as_json
      end

      private

      def assert_local_arguments(url, http_client, client_config)
        if url || client_config&.server_url
          raise ArgumentError, "Can't set the server URL for #{self.class}; the service provides it"
        elsif http_client && client_config
          raise ArgumentError, 'Cannot use both :http_client and :client_config'
        end
      end

View on GitHub (pinned to aa36b38e69)