question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[🐛 Bug]: Exception in FirefoxDriver constructor after assembly but not during development

See original GitHub issue

What happened?

When using FirefoxDriver in a Java program created using the maven-assembly-plugin, the FirefoxDriver constructor produces an exception and no driver is created. This, despite the usage of WebDriverManager and a functioning installation of Firefox. The issue does not occur when executing the program within IntelliJ IDEA.

How can we reproduce the issue?

Java snippet:

import io.github.bonigarcia.wdm.WebDriverManager;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.remote.service.DriverService;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.time.Duration;
import java.util.List;
import java.util.ServiceLoader;
import java.util.stream.Collectors;

public class Test {
    public static void main(final String[] args) {
        WebDriverManager.firefoxdriver().setup();

        final List<String> driverServiceBuilders = ServiceLoader.load(DriverService.Builder.class)
                .stream()
                .map(b -> b.type().getName().replaceAll("[A-Za-z.]+\\.", ""))
                .collect(Collectors.toUnmodifiableList());
        System.out.println(driverServiceBuilders);

        final var options = new FirefoxOptions();
        options.setHeadless(true);
        final var driver = new FirefoxDriver(options);
        final var wait = new WebDriverWait(driver, Duration.ofSeconds(10));

        try {
            // ...
        } catch (final WebDriverException e) {
            // ...
        } finally {
            driver.quit();
        }
    }
}

Corresponding Maven configuration:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>test</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>11</java.version>
        <resource.delimiter>@</resource.delimiter>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <maven.compiler.target>${java.version}</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>4.0.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/io.github.bonigarcia/webdrivermanager -->
        <dependency>
            <groupId>io.github.bonigarcia</groupId>
            <artifactId>webdrivermanager</artifactId>
            <version>5.0.3</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-simple -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.32</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>3.3.0</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                        <configuration>
                            <archive>
                                <manifest>
                                    <mainClass>Test</mainClass>
                                </manifest>
                            </archive>
                            <descriptorRefs>
                                <descriptorRef>jar-with-dependencies</descriptorRef>
                            </descriptorRefs>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Relevant log output

Running the code from within IntelliJ IDEA gives the following log:

[main] INFO io.github.bonigarcia.wdm.WebDriverManager - Using geckodriver 0.30.0 (resolved driver for Firefox 93)
[main] INFO io.github.bonigarcia.wdm.WebDriverManager - Exporting webdriver.gecko.driver as [...]\.cache\selenium\geckodriver\win64\0.30.0\geckodriver.exe
[ChromeDriverService$Builder, EdgeDriverService$Builder, GeckoDriverService$Builder, XpiDriverService$Builder, InternetExplorerDriverService$Builder, OperaDriverService$Builder, SafariDriverService$Builder, SafariTechPreviewDriverService$Builder]
1635979091778	geckodriver	INFO	Listening on 127.0.0.1:58965
1635979092654	mozrunner::runner	INFO	Running command: "C:\\Program Files\\Mozilla Firefox\\firefox.exe" "--marionette" "-headless" "--remote-debugging-port" "53683" "-no-remote" "-profile" "[...]"
*** You are running in headless mode.
1635979092860	Marionette	INFO	Marionette enabled
(... more successful geckodriver stuff ...)

Whereas the assembled jar outputs this:

[main] INFO io.github.bonigarcia.wdm.WebDriverManager - Using geckodriver 0.30.0 (resolved driver for Firefox 93)
[main] INFO io.github.bonigarcia.wdm.WebDriverManager - Exporting webdriver.gecko.driver as [...]\.cache\selenium\geckodriver\win64\0.30.0\geckodriver.exe
[ChromeDriverService$Builder]
Exception in thread "main" org.openqa.selenium.WebDriverException: Build info: version: '4.0.0', revision: '3a21814679'
System info: host: '[...]', ip: '[...]', os.name: 'Windows 10', os.arch: 'amd64', os.version: '10.0', java.version: '11.0.11'
Driver info: driver.version: FirefoxDriver
        at java.base/java.util.Optional.orElseThrow(Optional.java:408)
        at org.openqa.selenium.firefox.FirefoxDriver.toExecutor(FirefoxDriver.java:230)
        at org.openqa.selenium.firefox.FirefoxDriver.<init>(FirefoxDriver.java:186)
        at Test.main(Test.java:25)

Note especially that the list of available driver service builders is reduced from eight instances to one. Internet Explorer, Edge, Chrome, and Firefox are all installed on my system, and I have not installed any drivers outside of those managed by WebDriverManager.

Operating System

Windows 10

Selenium version

4.0.0

What are the browser(s) and version(s) where you see this issue?

Firefox latest

What are the browser driver(s) and version(s) where you see this issue?

GeckoDriver 0.30.0

Are you using Selenium Grid?

No response

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:2
  • Comments:16 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
TobiasHeinencommented, Feb 7, 2022

The proposed solution is a workaround that only works in Maven - the root problem, however, remains unsolved. Since everything worked fine on 3.141.59 (as I noted above), I believe this regression was introduced with the legacy driver split for Firefox back in November 2018. That said, the issue is exclusive to Firefox:

FirefoxDriver#toExecutor checks, at runtime, whether there is any file named META-INF/services/org.openqa.selenium.remote.service.DriverService$Builder in the classpath whose class is a FirefoxDriverService extension and satisfies the isLegacy flag as required. When, during packaging, the service descriptors for all but the first DriverService go missing, this check will not find any FirefoxDriverService even though the classes for the GeckoDriverService are present.

Bypassing toExecutor, such as by calling new FirefoxDriver(GeckoDriverService.createDefaultService(), options), also bypasses the issue entirely.

Assuming this is possible, I believe the issue should be resolved by correcting the legacy check to not rely on the service entry in the classpath. Independent of that, the exception message needs to be improved. Since the issue apparently occurs in both Maven and Gradle in their default configurations, a lot of unsuspecting developers will encounter it. A googleable message, even if it only refers to a missing (non-)legacy Firefox driver service, will help with finding resources for workarounds. best placed in the Selenium documentation.

1reaction
pujaganicommented, Dec 8, 2021

Thank you for providing the details and sharing the findings. @jonas-haeusler Your diagnosis for the problem is right. However, after spending sufficient time digging into and seeing how Selenium packages things, I don’t think there is something we are missing there. Such a use case comes up every now and then when there are multiple implementations for the provider. It is essentially how the assembly handles it. I also spent time trying out the metaInf-services handler of the maven-assembly-plugin, initially faced an issue with different plugin versions but got that working. I hope this helps since maven-assembly-plugin provides a mechanism to handle this. The assembly file:

<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
  <!-- TODO: a jarjar format would be better -->
  <id>jar-with-dependencies</id>
  <formats>
    <format>jar</format>
  </formats>
  <includeBaseDirectory>false</includeBaseDirectory>
  <dependencySets>
    <dependencySet>
      <outputDirectory>/</outputDirectory>
      <useProjectArtifact>true</useProjectArtifact>
      <unpack>true</unpack>
      <scope>runtime</scope>
    </dependencySet>
  </dependencySets>
  <containerDescriptorHandlers>
    <containerDescriptorHandler>
      <handlerName>metaInf-services</handlerName>
    </containerDescriptorHandler>
  </containerDescriptorHandlers>
</assembly>

Sharing the pom.xml below:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>groupId</groupId>
  <artifactId>tutorial</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <properties>
    <java.version>9</java.version>
    <maven.compiler.source>${java.version}</maven.compiler.source>
    <maven.compiler.target>${java.version}</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-assembly-plugin</artifactId>
      <version>3.3.0</version>
      <type>maven-plugin</type>
    </dependency>
<!--    <dependency>-->
<!--      <groupId>org.seleniumhq.selenium</groupId>-->
<!--      <artifactId>selenium-devtools-v87</artifactId>-->
<!--      <version>4.0.0-beta-3</version>-->
<!--    </dependency>-->
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.8.0</version>
    </dependency>
    <dependency>
      <groupId>org.seleniumhq.selenium</groupId>
      <artifactId>selenium-java</artifactId>
      <version>4.0.0</version>
    </dependency>
    <dependency>
      <groupId>com.google.guava</groupId>
      <artifactId>guava</artifactId>
      <version>24.0-jre</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/junit/junit -->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-api</artifactId>
      <version>5.6.0</version>
      <scope>test</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.assertj/assertj-core -->
    <dependency>
      <groupId>org.assertj</groupId>
      <artifactId>assertj-core</artifactId>
      <version>3.17.2</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.testng</groupId>
      <artifactId>testng</artifactId>
      <version>7.4.0</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>io.opentelemetry</groupId>
      <artifactId>opentelemetry-exporter-jaeger</artifactId>
      <version>1.0.0</version>
      <exclusions>
        <exclusion>  <!-- declare the exclusion here -->
          <groupId>io.opentelemetry</groupId>
          <artifactId>opentelemetry-api</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <!-- https://mvnrepository.com/artifact/io.grpc/grpc-netty-shaded -->
    <dependency>
      <groupId>io.grpc</groupId>
      <artifactId>grpc-netty-shaded</artifactId>
      <version>1.42.1</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.7.0</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
          <encoding>UTF-8</encoding>
        </configuration>
      </plugin>
<!--      <plugin>-->
<!--        <groupId>org.apache.maven.plugins</groupId>-->
<!--        <artifactId>maven-dependency-plugin</artifactId>-->
<!--        <executions>-->
<!--          <execution>-->
<!--            <id>copy-dependencies</id>-->
<!--            <phase>prepare-package</phase>-->
<!--            <goals>-->
<!--              <goal>copy-dependencies</goal>-->
<!--            </goals>-->
<!--            <configuration>-->
<!--              <outputDirectory>-->
<!--                ${project.build.directory}/libs-->
<!--              </outputDirectory>-->
<!--            </configuration>-->
<!--          </execution>-->
<!--        </executions>-->
<!--      </plugin>-->
<!--      <plugin>-->
<!--        <groupId>org.apache.maven.plugins</groupId>-->
<!--        <artifactId>maven-jar-plugin</artifactId>-->
<!--        <configuration>-->
<!--          <archive>-->
<!--            <manifest>-->
<!--              <addClasspath>true</addClasspath>-->
<!--              <classpathPrefix>libs/</classpathPrefix>-->
<!--              <mainClass>-->
<!--                com.company.MainHttpFirefox-->
<!--              </mainClass>-->
<!--            </manifest>-->
<!--          </archive>-->
<!--        </configuration>-->
<!--      </plugin>-->


      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <inherited>true</inherited>
        <version>3.3.0</version>
        <configuration>
          <appendAssemblyId>true</appendAssemblyId>
          <descriptors>
            <descriptor>src/main/assembly/jar-with-dependencies.xml</descriptor>
          </descriptors>
        </configuration>
        <executions>
          <execution>
            <id>make-assembly</id>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
            <configuration>
              <archive>
                <manifest>
                  <mainClass>
                    com.company.MainHttpFirefox
                  </mainClass>
                  <addClasspath>true</addClasspath>-->
                </manifest>
              </archive>
              <descriptors>
                <descriptor>src/main/assembly/jar-with-dependencies.xml</descriptor>
              </descriptors>
            </configuration>
          </execution>
        </executions>
      </plugin>
<!--      <plugin>-->
<!--        <artifactId>maven-shade-plugin</artifactId>-->
<!--        <version>1.4</version>-->
<!--        <executions>-->
<!--          <execution>-->
<!--            <phase>package</phase>-->
<!--            <goals>-->
<!--              <goal>shade</goal>-->
<!--            </goals>-->
<!--            <configuration>-->
<!--              <finalName>${project.artifactId}-by-shade</finalName>-->
<!--              <transformers>-->
<!--                <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>-->
<!--                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">-->
<!--                  <mainClass>com.company.MainHttpFirefox</mainClass>-->
<!--                </transformer>-->
<!--              </transformers>-->
<!--            </configuration>-->
<!--          </execution>-->
<!--        </executions>-->
<!--      </plugin>-->
    </plugins>
  </build>

</project>

I simply do: mvn clean package

Running the appropriate jar: java -cp /Users/Puja/Documents/GitHub/selenium-java-webdriver-test/target/tutorial-1.0-SNAPSHOT-jar-with-dependencies.jar com.company.MainHttpFirefox

In addition, using the maven-shade plugin, also works like a charm. The commented-out plugins in the pom shared above include the other maven plugins that work as well.

Sharing some references and the similar situations faced that I found on the Internet that helped me understand :

  1. https://dzone.com/articles/jar-deps-dont-meta
  2. http://www.ostack.cn/?qa=942526/
  3. https://stackoverflow.com/questions/47310215/merging-meta-inf-services-files-with-maven-assembly-plugin
  4. https://issues.apache.org/jira/browse/MASSEMBLY-209 (Similar issue was faced by Spring Framework META-INF - https://issues.apache.org/jira/browse/MASSEMBLY-360)

I recommend trying out the custom assembly file approach since that is the solution provided by the assembly plugins themselves. @tobli @Tejareddy1

Read more comments on GitHub >

github_iconTop Results From Across the Web

c# - OpenQA.Selenium.WebDriverException: 'Cannot start the ...
I'm getting the following error when I try to open the EdgeDriver. ... The FirefoxDriver and ChromeDriver work just fine. ... This is...
Read more >
How to fix common Selenium errors? - Ultimate QA
Selenium webdriver errors that are commonly faced by QA Engineers. This article covers all the common errors including Firefox and Selenium ...
Read more >
BrowserMob Proxy Selenium Java Tutorial with an Example!
In this article the BrowserMob Proxy Selenium Java example shows how we can get performance related data from selenium test scenarios.
Read more >
xUnit Testing Tutorial: Unit Testing With Selenium C# ...
xUnit is an open-source unit testing framework for .NET. This xUnit testing tutorial will help you learn how to run unit testing with ......
Read more >
dotnet/CHANGELOG - external/selenium - Git at Google
must be a subclass of By, and it must expose a public constructor that takes ... Handled the case where a JSON Wire...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found