Skip to content

[🐛 Bug]: FindElements By ClassName doesn't work inside Shadow root #15961

Open
@wojciechkaczmarek

Description

@wojciechkaczmarek

Description

When trying to invoke SearchContext.findElements() with By.className() an InvalidArgumentException is thrown unexpectedly.

The By itself is correct and the shadow DOM's host element exists in page at the time of invocation.

I have not tested it with older versions of browser, tried several versions of Selenium from 4.13 to 4.33.

The issue is not likely a duplicate of #10025 , since it was resolved as browser issue.

OS is Ubuntu 24.04, Firefox version is 139.0.4.

A workaround is possible, moving the entire action into JS injection, in this case:

wait.until((driver) -> (Boolean) ((JavascriptExecutor) driver).executeScript("""
            let roots = document.getElementsByTagName('div');
            for (i = 0; i < roots.length; i++) {
              if (roots.item(i).shadowRoot != null) {
                let el = roots.item(i).shadowRoot.querySelector('.ft-reg-bubble-close');
                if (el != undefined) {
                  el.click();
                  return true;
                }
              }
            }
            return false;
            """));

Stack trace:

Exception in thread "main" org.openqa.selenium.InvalidArgumentException: unknown variant `class name`, expected one of `css selector`, `link text`, `partial link text`, `tag name`, `xpath` at line 2 column 23
Build info: version: '4.33.0', revision: '2c6aaad03a'
System info: os.name: 'Linux', os.arch: 'amd64', os.version: '6.11.0-26-generic', java.version: '23.0.2'
Driver info: org.openqa.selenium.firefox.FirefoxDriver
Command: [ccb41492-5a0e-4f0f-8d99-7a65861abe75, findElementsFromShadowRoot {using=class name, shadowId=e10c00e0-c4ab-4d4c-a0ce-6ba322d0bc6c, value=ft-reg-bubble-close}]
Capabilities {acceptInsecureCerts: true, browserName: firefox, browserVersion: 139.0.4, moz:accessibilityChecks: false, moz:buildID: 20250609225024, moz:geckodriverVersion: 0.36.0, moz:headless: false, moz:platformVersion: 6.11.0-26-generic, moz:processID: 652353, moz:profile: /tmp/rust_mozprofiler3PhdD, moz:shutdownTimeout: 60000, moz:webdriverClick: true, moz:windowless: false, pageLoadStrategy: normal, platformName: linux, proxy: Proxy(), setWindowRect: true, strictFileInteractability: false, timeouts: {implicit: 0, pageLoad: 300000, script: 30000}, unhandledPromptBehavior: dismiss and notify, userAgent: Mozilla/5.0 (X11; Ubuntu; L...}
Session ID: ccb41492-5a0e-4f0f-8d99-7a65861abe75
	at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62)
	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:501)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:485)
	at org.openqa.selenium.remote.ErrorCodec.decode(ErrorCodec.java:167)
	at org.openqa.selenium.remote.codec.w3c.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:138)
	at org.openqa.selenium.remote.codec.w3c.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:50)
	at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:215)
	at org.openqa.selenium.remote.service.DriverCommandExecutor.invokeExecute(DriverCommandExecutor.java:216)
	at org.openqa.selenium.remote.service.DriverCommandExecutor.execute(DriverCommandExecutor.java:174)
	at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:544)
	at org.openqa.selenium.remote.ElementLocation$ElementFinder$2.findElements(ElementLocation.java:182)
	at org.openqa.selenium.remote.ElementLocation.findElements(ElementLocation.java:103)
	at org.openqa.selenium.remote.RemoteWebDriver.findElements(RemoteWebDriver.java:380)
	at org.openqa.selenium.remote.ShadowRoot.findElements(ShadowRoot.java:47)

Reproducible Code

public class Main {
    public static void main(String... args) {
        FirefoxOptions options = new FirefoxOptions();
        // please change the binary path, as I set it manually to work around another issue
        options.setBinary(Path.of("/snap/firefox/current/usr/lib/firefox/firefox"));
        WebDriver driver = new FirefoxDriver(options);
        driver.get("https://neal.fun/stimulation-clicker/");

        FluentWait<WebDriver> wait = new FluentWait<>(driver)
            .withTimeout(Duration.ofMillis(5000))
            .pollingEvery(Duration.ofMillis(100))
            .ignoring(StaleElementReferenceException.class)
            .ignoring(NoSuchElementException.class);

        wait.until(ExpectedConditions.visibilityOfElementLocatedBy(By.classname("fc-cta-consent"))).click();

        wait.until((driver) -> driver.findElements(By.tagName("div"))
                .stream()
                .map(webElement -> {
                    try {
                        return webElement.getShadowRoot();
                    } catch (NoSuchShadowRootException e) {
                        return null;
                    }
                }).filter(Objects::nonNull)
                .findFirst()
                // this is not Selenium, but java.util NSE - doesn't matter in this case, and has simpler ctor
                .orElseThrow(NoSuchElementException::new)

            // ---InvalidArgumentException is thrown here---
            ).findElements(By.className("ft-reg-bubble-close"))

            .getFirst()
            .click();
    }
}

Debugging Logs

<record>
<date>2025-06-25T17:03:38.639626279Z</date>
<millis>1750871018639</millis>
<nanos>626279</nanos>
<sequence>532</sequence>
<logger>org.openqa.selenium.remote.RemoteWebDriver</logger>
<level>FINE</level>
<class>org.openqa.selenium.remote.RemoteWebDriver</class>
<method>log</method>
<thread>1</thread>
<message>Executing: getElementShadowRoot [ccb41492-5a0e-4f0f-8d99-7a65861abe75, getElementShadowRoot {id=3e8bf436-2a6b-43a7-b124-6b1131acc063}]</message>
</record>
<record>
<date>2025-06-25T17:03:38.640005967Z</date>
<millis>1750871018640</millis>
<nanos>5967</nanos>
<sequence>533</sequence>
<logger>org.openqa.selenium.remote.http.jdk.JdkHttpClient</logger>
<level>FINE</level>
<class>org.openqa.selenium.remote.http.jdk.JdkHttpClient</class>
<method>execute0</method>
<thread>39</thread>
<message>Executing request: (GET) /session/ccb41492-5a0e-4f0f-8d99-7a65861abe75/element/3e8bf436-2a6b-43a7-b124-6b1131acc063/shadow</message>
</record>
<record>
<date>2025-06-25T17:03:38.645499870Z</date>
<millis>1750871018645</millis>
<nanos>499870</nanos>
<sequence>534</sequence>
<logger>org.openqa.selenium.remote.http.jdk.JdkHttpClient</logger>
<level>FINE</level>
<class>org.openqa.selenium.remote.http.jdk.JdkHttpClient</class>
<method>execute0</method>
<thread>39</thread>
<message>Ending request (GET) /session/ccb41492-5a0e-4f0f-8d99-7a65861abe75/element/3e8bf436-2a6b-43a7-b124-6b1131acc063/shadow in 5ms</message>
</record>
<record>
<date>2025-06-25T17:03:38.646399532Z</date>
<millis>1750871018646</millis>
<nanos>399532</nanos>
<sequence>535</sequence>
<logger>org.openqa.selenium.remote.RemoteWebDriver</logger>
<level>FINE</level>
<class>org.openqa.selenium.remote.RemoteWebDriver</class>
<method>log</method>
<thread>1</thread>
<message>Executed: getElementShadowRoot (Response: SessionID: ccb41492-5a0e-4f0f-8d99-7a65861abe75, State: success, Value: {shadow-6066-11e4-a52e-4f735466cecf=e10c00e0-c4ab-4d4c-a0ce-6ba322d0bc6c})</message>
</record>
<record>
<date>2025-06-25T17:03:38.647918667Z</date>
<millis>1750871018647</millis>
<nanos>918667</nanos>
<sequence>536</sequence>
<logger>org.openqa.selenium.remote.RemoteWebDriver</logger>
<level>FINE</level>
<class>org.openqa.selenium.remote.RemoteWebDriver</class>
<method>log</method>
<thread>1</thread>
<message>Executing: findElementsFromShadowRoot [ccb41492-5a0e-4f0f-8d99-7a65861abe75, findElementsFromShadowRoot {using=class name, shadowId=e10c00e0-c4ab-4d4c-a0ce-6ba322d0bc6c, value=ft-reg-bubble-close}]</message>
</record>
<record>
<date>2025-06-25T17:03:38.649520961Z</date>
<millis>1750871018649</millis>
<nanos>520961</nanos>
<sequence>537</sequence>
<logger>org.openqa.selenium.remote.http.jdk.JdkHttpClient</logger>
<level>FINE</level>
<class>org.openqa.selenium.remote.http.jdk.JdkHttpClient</class>
<method>execute0</method>
<thread>39</thread>
<message>Executing request: (POST) /session/ccb41492-5a0e-4f0f-8d99-7a65861abe75/shadow/e10c00e0-c4ab-4d4c-a0ce-6ba322d0bc6c/elements</message>
</record>
<record>
<date>2025-06-25T17:03:38.653411850Z</date>
<millis>1750871018653</millis>
<nanos>411850</nanos>
<sequence>538</sequence>
<logger>org.openqa.selenium.remote.http.jdk.JdkHttpClient</logger>
<level>FINE</level>
<class>org.openqa.selenium.remote.http.jdk.JdkHttpClient</class>
<method>execute0</method>
<thread>39</thread>
<message>Ending request (POST) /session/ccb41492-5a0e-4f0f-8d99-7a65861abe75/shadow/e10c00e0-c4ab-4d4c-a0ce-6ba322d0bc6c/elements in 3ms</message>
</record>
<record>
<date>2025-06-25T17:03:38.653979049Z</date>
<millis>1750871018653</millis>
<nanos>979049</nanos>
<sequence>539</sequence>
<logger>org.openqa.selenium.remote.codec.w3c.W3CHttpResponseCodec</logger>
<level>FINE</level>
<class>org.openqa.selenium.remote.codec.w3c.W3CHttpResponseCodec</class>
<method>decode</method>
<thread>1</thread>
<message>Processing an error</message>
</record>
<record>
<date>2025-06-25T17:03:38.655661503Z</date>
<millis>1750871018655</millis>
<nanos>661503</nanos>
<sequence>540</sequence>
<logger>org.openqa.selenium.remote.RemoteWebDriver</logger>
<level>FINE</level>
<class>org.openqa.selenium.remote.RemoteWebDriver</class>
<method>log</method>
<thread>1</thread>
<message>Executed: findElementsFromShadowRoot (Response: SessionID: ccb41492-5a0e-4f0f-8d99-7a65861abe75, State: invalid argument, Value: org.openqa.selenium.InvalidArgumentException: unknown variant `class name`, expected one of `css selector`, `link text`, `partial link text`, `tag name`, `xpath` at line 2 column 23 Build info: version: '4.33.0', revision: '2c6aaad03a' System info: os.name: 'Linux', os.arch: 'amd64', os.version: '6.11.0-26-generic', java.version: '23.0.2' Driver info: driver.version: RemoteWebDriver)</message>
</record>

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions