SeleniumHQ/selenium · critical · Error::NoSuchDriverError

Unable to obtain #{@service.class::EXECUTABLE}

Error message

Unable to obtain #{@service.class::EXECUTABLE}

What it means

Raised as Error::NoSuchDriverError from DriverFinder#paths when locating the driver (or browser) executable fails for ANY reason. The rescue catches StandardError broadly, logs the real message at error level with id: :driver_finder, then re-raises this generic message naming @service.class::EXECUTABLE (e.g. 'chromedriver', 'geckodriver'). The underlying cause is hidden in the logged exception, not in the raised message.

Source

Thrown at rb/lib/selenium/webdriver/common/driver_finder.rb:57

      def driver_path
        paths[:driver_path]
      end

      def browser_path?
        !browser_path.nil? && !browser_path.empty?
      end

      private

      def paths
        @paths ||= begin
          path = @service.executable_path || env_path || class_path
          path ? paths_from_service(path) : paths_from_manager
        rescue StandardError => e
          WebDriver.logger.error("Exception occurred: #{e.message}", id: :driver_finder)
          WebDriver.logger.error("Backtrace:\n\t#{e.backtrace&.join("\n\t")}", id: :driver_finder)
          raise Error::NoSuchDriverError, "Unable to obtain #{@service.class::EXECUTABLE}"
        end
      end

      def env_path
        ENV.fetch(@service.class::DRIVER_PATH_ENV_KEY, nil)
      end

      def class_path
        path = @service.class.driver_path
        path.is_a?(Proc) ? path.call : path
      end

      def paths_from_service(path)
        exe = @service.class::EXECUTABLE
        WebDriver.logger.debug("Skipping Selenium Manager; path to #{exe} specified in service class: #{path}",
                               id: :driver_finder)
        Platform.assert_executable(path)
        {driver_path: path}

View on GitHub (pinned to aa36b38e69)

Solutions

  1. Re-run with WebDriver.logger.level = :debug (or set SELENIUM_LOG_LEVEL=debug); the rescue logs 'Exception occurred: <real message>' and the backtrace under id: :driver_finder — read that line first, it states the true cause.
  2. Pre-place the driver and point at it explicitly: set the service env var (e.g. SELENIUM_CHROMEDRIVER_PATH=/abs/path/chromedriver) or Service.executable_path, and confirm the file exists, is non-empty, and has the executable bit (chmod +x).
  3. Ensure the target browser is actually installed and discoverable on PATH, and that Selenium Manager (bundled binary under selenium-manager) can run and reach its download host — check network/proxy/firewall in air-gapped CI.
  4. Match versions: the driver major version must be compatible with the installed browser major version; in pinned-driver setups downgrade/upgrade the driver to match.

Example fix

// before
options = Selenium::WebDriver::Chrome::Options.new
driver = Selenium::WebDriver.for(:chrome, options: options) # => NoSuchDriverError: Unable to obtain chromedriver

# after
path = "/usr/local/bin/chromedriver"
raise "missing #{path}" unless File.executable?(path)
service = Selenium::WebDriver::Service.chrome(executable_path: path)
driver = Selenium::WebDriver.for(:chrome, options: options, service: service)
Defensive patterns

Strategy: validation

Validate before calling

# Run before Selenium::WebDriver.for(...)
service = Selenium::WebDriver::Service.chrome
driver_path = ENV[service.class::DRIVER_PATH_ENV_KEY] || service.class.driver_path
driver_path = driver_path.call if driver_path.is_a?(Proc)
if driver_path
  raise "driver not executable: #{driver_path}" unless File.file?(driver_path) && File.executable?(driver_path)
end
# Let Selenium Manager resolve only when no explicit path is set; check the browser binary too:
browser = Selenium::WebDriver::Chrome.path || `which google-chrome 2>/dev/null`.strip
raise "chrome binary not found on PATH" if browser.empty?

Try / catch

begin
  driver = Selenium::WebDriver.for(:chrome, options: options)
rescue Selenium::WebDriver::Error::NoSuchDriverError => e
  WebDriver.logger.replay(id: :driver_finder) if WebDriver.logger.respond_to?(:replay)
  raise "Driver init failed (#{e.message}); run with SELENIUM_LOG_LEVEL=debug to see the underlying cause"
end

Prevention

When it happens

Trigger: Constructing a Driver (Selenium::WebDriver.for(:chrome), etc.) triggers DriverFinder.new(options, service).driver_path. It fails when: (a) SeleniumManager.binary_paths returns no/invalid path (no network, browser not installed, unsupported browser version), (b) an explicit path from service.executable_path / DRIVER_PATH_ENV_KEY / Service.driver_path is missing or not executable (Platform.assert_executable raises), or (c) the configured Proc in driver_path raises.

Common situations: CI/image without the browser installed; Selenium Manager cannot reach its download mirror (air-gapped / proxy); a pinned driver path points at a stale or non-executable file after an OS update or docker layer change; upgrading the browser past the last driver Selenium Manager knows about; on Windows a path with a missing .exe extension or lacking execute permission.

Related errors


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