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
- 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.
- 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).
- 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.
- 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
- Pin a known-good driver/browser pair in CI images and set SELENIUM_*_PATH env vars to absolute, executable paths.
- In air-gapped CI, pre-download drivers and disable Selenium Manager network access by pointing services at the local files.
- Run with SELENIUM_LOG_LEVEL=debug during driver setup so the underlying 'Exception occurred:' line is visible before this generic error.
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
- unsupported platform: #{Platform.os}
- Unsuccessful command executed: #{command}; #{e.message}
- Unable to obtain browser driver. For more informatio
- Unable to obtain Selenium Manager at ${filePath}
- Error executing command for ${smBinary} with ${args}: ${erro
AI-assisted analysis of SeleniumHQ/selenium@aa36b38e69 (2026-08-14).
Data as JSON: /api/errors/664b641563ef9ff2.
Report an issue: GitHub.