SeleniumHQ/selenium · error · ArgumentError

#{self.class} needs :options to be set

Error message

#{self.class} needs :options to be set

What it means

Raised by Remote::Driver#process_options when neither :options nor :capabilities is provided to the driver constructor. Remote::Driver requires at least one to know what browser session to request from the server — without it, the W3C new-session request would have no 'capabilities' field and every server would reject it.

Source

Thrown at rb/lib/selenium/webdriver/remote/driver.rb:74

        end

        def devtools_url
          capabilities['se:cdp']
        end

        def devtools_version
          cdp_version = capabilities['se:cdpVersion']&.split('.')&.first
          raise Error::WebDriverError, 'DevTools is not supported by the Remote Server' unless cdp_version

          Integer(cdp_version)
        end

        def process_options(options, capabilities)
          if options && capabilities
            msg = "Don't use both :options and :capabilities when initializing #{self.class}, prefer :options"
            raise ArgumentError, msg
          elsif options.nil? && capabilities.nil?
            raise ArgumentError, "#{self.class} needs :options to be set"
          end
          options ? options.as_json : generate_capabilities(capabilities)
        end

        def generate_capabilities(capabilities)
          Array(capabilities).map { |cap|
            if cap.is_a? Symbol
              cap = WebDriver::Options.send(cap)
            elsif !cap.respond_to? :as_json
              msg = ":capabilities parameter only accepts objects responding to #as_json which #{cap.class} does not"
              raise ArgumentError, msg
            end
            cap.as_json
          }.inject(:merge)
        end
      end # Driver
    end # Remote
  end # WebDriver

View on GitHub (pinned to aa36b38e69)

Solutions

  1. Provide an Options object: Selenium::WebDriver.for(:remote, url: url, options: Selenium::WebDriver::Options.chrome).
  2. If using a dynamic browser name, build options conditionally but ensure the result is never nil: options = Selenium::WebDriver::Options.send(browser_name.to_sym).
  3. Validate your config hash has a non-nil :options value before passing it to the driver constructor.

Example fix

# before
driver = Selenium::WebDriver.for(:remote, url: url)

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

Strategy: validation

Validate before calling

# Ensure options is non-nil:
raise ArgumentError, ':options is required for :remote' unless config[:options] || config[:capabilities]
# or set a default:
config[:options] ||= Selenium::WebDriver::Options.chrome
Selenium::WebDriver.for(:remote, **config)

Type guard

def has_session_config?(config)
  !config[:options].nil? || !config[:capabilities].nil?
end

Try / catch

begin
  Selenium::WebDriver.for(:remote, **config)
rescue ArgumentError => e
  raise unless e.message.include?('needs :options')
  Selenium::WebDriver.for(:remote, options: Selenium::WebDriver::Options.chrome, **config)
end

Prevention

When it happens

Trigger: Calling Selenium::WebDriver.for(:remote, url: url) with no options or capabilities. Passing an empty hash or only :url/:http_client. A config builder that conditionally sets options but the condition evaluates to nil.

Common situations: Forgetting to specify browser options when switching from a local driver (which infers them from the driver type) to :remote. Nil-valued config keys being silently dropped by double-splat. Refactoring that moved options construction behind a conditional branch that wasn't taken.

Related errors


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