gRPC exception related with NameResolverProvider

I have a gRPC server written in Java, that is trying to access Firestore and other services, through a Service Account that has Project Owner roles. The server ran successfully plenty of times, but when I tried to run again, this happened:

Exception in thread "main" java.util.ServiceConfigurationError: io.grpc.NameResolverProvider: Provider io.grpc.grpclb.SecretGrpclbNameResolverProvider$Provider could not be instantiated
    at java.util.ServiceLoader.fail(ServiceLoader.java:232)
    at java.util.ServiceLoader.access$100(ServiceLoader.java:185)
    at java.util.ServiceLoader$LazyIterator.nextService(ServiceLoader.java:384)
    at java.util.ServiceLoader$LazyIterator.next(ServiceLoader.java:404)
    at java.util.ServiceLoader$1.next(ServiceLoader.java:480)
    at io.grpc.ServiceProviders.loadAll(ServiceProviders.java:67)
    at io.grpc.NameResolverRegistry.getDefaultRegistry(NameResolverRegistry.java:101)
    at io.grpc.internal.AbstractManagedChannelImplBuilder.<init>(AbstractManagedChannelImplBuilder.java:107)
    at io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder.<init>(NettyChannelBuilder.java:136)
    at io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder.<init>(NettyChannelBuilder.java:131)
    at io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder.forAddress(NettyChannelBuilder.java:117)
    at io.grpc.netty.shaded.io.grpc.netty.NettyChannelProvider.builderForAddress(NettyChannelProvider.java:37)
    at io.grpc.netty.shaded.io.grpc.netty.NettyChannelProvider.builderForAddress(NettyChannelProvider.java:23)
    at io.grpc.ManagedChannelBuilder.forAddress(ManagedChannelBuilder.java:39)
    at com.google.api.gax.grpc.InstantiatingGrpcChannelProvider.createSingleChannel(InstantiatingGrpcChannelProvider.java:270)
    at com.google.api.gax.grpc.InstantiatingGrpcChannelProvider.access$1500(InstantiatingGrpcChannelProvider.java:71)
    at com.google.api.gax.grpc.InstantiatingGrpcChannelProvider$1.createSingleChannel(InstantiatingGrpcChannelProvider.java:202)
    at com.google.api.gax.grpc.ChannelPool.create(ChannelPool.java:72)
    at com.google.api.gax.grpc.InstantiatingGrpcChannelProvider.createChannel(InstantiatingGrpcChannelProvider.java:209)
    at com.google.api.gax.grpc.InstantiatingGrpcChannelProvider.getTransportChannel(InstantiatingGrpcChannelProvider.java:192)
    at com.google.api.gax.rpc.ClientContext.create(ClientContext.java:155)
    at com.google.api.gax.rpc.ClientContext.create(ClientContext.java:122)
    at com.google.cloud.firestore.spi.v1.GrpcFirestoreRpc.<init>(GrpcFirestoreRpc.java:122)
    at com.google.cloud.firestore.FirestoreOptions$DefaultFirestoreRpcFactory.create(FirestoreOptions.java:90)
    at com.google.cloud.firestore.FirestoreOptions$DefaultFirestoreRpcFactory.create(FirestoreOptions.java:82)
    at com.google.cloud.ServiceOptions.getRpc(ServiceOptions.java:561)
    at com.google.cloud.firestore.FirestoreOptions.getFirestoreRpc(FirestoreOptions.java:385)
    at com.google.cloud.firestore.FirestoreImpl.<init>(FirestoreImpl.java:67)
    at com.google.cloud.firestore.FirestoreOptions$DefaultFirestoreFactory.create(FirestoreOptions.java:73)
    at com.google.cloud.firestore.FirestoreOptions$DefaultFirestoreFactory.create(FirestoreOptions.java:66)
    at com.google.cloud.ServiceOptions.getService(ServiceOptions.java:541)
    at services.FirestoreServiceActions.<init>(FirestoreServiceActions.java:25)
    at CNTextServer.main(CNTextServer.java:47)
Caused by: java.lang.VerifyError: Cannot inherit from final class
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:756)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:355)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
    at java.lang.Class.getDeclaredConstructors0(Native Method)
    at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671)
    at java.lang.Class.getConstructor0(Class.java:3075)
    at java.lang.Class.newInstance(Class.java:412)
    at java.util.ServiceLoader$LazyIterator.nextService(ServiceLoader.java:380)
    ... 30 more

To simplify things and to turnaround some major problems that may happen on IntelliJ Idea, I’ve created a much simpler (Maven) project that just has some code to start the server, and it worked fine, the server runs perfectly. Although, when I add the line that initializes the Firestore service, the same Exceptions are thrown.

I have an environment variable (GOOGLE_APPLICATION_CREDENTIALS) pointing to a key of a service account that has Project Owner roles, just like I’ve mentioned before. I’ve also tried the FileInputStream alternative, pointing to the key, with no success.

The code of my simpler (Maven) project is:

private static final int SERVICE_PORT = 8000;
private Firestore firestoreService

public static void main(String[] args) {
        try {
            System.out.println("--> SETTING UP THE SERVER...");

            GoogleCredentials credentials = GoogleCredentials.fromStream(new FileInputStream(SERVICE_ACCOUNT_KEY_PATH));

            this.firestoreService = FirestoreOptions.newBuilder().setCredentials(credentials).build().getService();

            Server service = ServerBuilder
                    .forPort(SERVICE_PORT)
                    .addService(new CNTextServer())
                    .build();

            service.start();

            System.out.println("--- SERVER STARTED. LISTENING ON PORT " + SERVICE_PORT);
            System.out.println("--> PRESS 'ENTER' TO STOP THE SERVER");
            Scanner scanner = new Scanner(System.in);
            scanner.nextLine();

            System.out.println("<-- SERVER SHUTTING DOWN...");
            service.shutdown();
        } catch (Exception ex) {
            System.out.println("### EXCEPTION ON SERVER.MAIN() ###n" + ex.getMessage());
        }
    }

The dependencies on the Maven pom.xml file are:

 <dependencies>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-netty-shaded</artifactId>
            <version>1.28.0</version>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-protobuf</artifactId>
            <version>1.28.0</version>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-stub</artifactId>
            <version>1.28.0</version>
        </dependency>
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>google-cloud-firestore</artifactId>
            <version>1.34.0</version>
        </dependency>
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>google-cloud-storage</artifactId>
            <version>1.108.0</version>
        </dependency>
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>google-cloud-pubsub</artifactId>
            <version>1.106.0</version>
        </dependency>
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>google-cloud-compute</artifactId>
            <version>0.118.0-alpha</version>
        </dependency>
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>google-cloud-vision</artifactId>
            <version>1.99.3</version>
        </dependency>
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>google-cloud-translate</artifactId>
            <version>1.94.5</version>
        </dependency>
        <dependency>
            <groupId>leic.cn.li62d-g04</groupId>
            <artifactId>CNTextContract</artifactId>
            <version>1.0</version>
            <scope>system</scope>
            <systemPath>${basedir}/../CNTextContract/target/CNTextContract-1.0-SNAPSHOT.jar</systemPath>
        </dependency>
    </dependencies>

Answer

Running mvn dependency:tree we see:

[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ examples ---
[INFO] com.example:examples:jar:1.0.0
[INFO] +- io.grpc:grpc-netty-shaded:jar:1.28.0:compile
[INFO] |  - io.grpc:grpc-core:jar:1.28.0:compile (version selected from constraint [1.28.0,1.28.0])
[INFO] +- io.grpc:grpc-protobuf:jar:1.28.0:compile
[INFO] |  +- io.grpc:grpc-api:jar:1.28.0:compile
[INFO] |  +- com.google.protobuf:protobuf-java:jar:3.11.0:compile
[INFO] |  +- com.google.guava:guava:jar:28.1-android:compile
[INFO] |  +- com.google.api.grpc:proto-google-common-protos:jar:1.17.0:compile
[INFO] |  - io.grpc:grpc-protobuf-lite:jar:1.28.0:compile
[INFO] +- io.grpc:grpc-stub:jar:1.28.0:compile
[INFO] +- com.google.cloud:google-cloud-firestore:jar:1.34.0:compile
[INFO] |  +- com.google.cloud:google-cloud-core-grpc:jar:1.93.5:compile
...
[INFO] |  +- io.grpc:grpc-context:jar:1.29.0:compile
[INFO] |  +- com.google.api:gax:jar:1.56.0:compile
[INFO] |  +- com.google.auth:google-auth-library-oauth2-http:jar:0.20.0:compile
[INFO] |  +- com.google.errorprone:error_prone_annotations:jar:2.3.4:compile
[INFO] |  +- org.codehaus.mojo:animal-sniffer-annotations:jar:1.18:compile
[INFO] |  +- com.google.api:gax-grpc:jar:1.56.0:compile
[INFO] |  +- io.grpc:grpc-auth:jar:1.29.0:compile
[INFO] |  +- io.grpc:grpc-alts:jar:1.29.0:compile
[INFO] |  +- io.grpc:grpc-grpclb:jar:1.29.0:compile

The problem is that grpc-core is too old. You can see io.grpc:grpc-core:jar:1.28.0 and io.grpc:grpc-grpclb:jar:1.29.0:compile. grpclb depends on grpc-core 1.29.0. In 1.29.0 GrpclbNameResolver was added that extends DnsNameResolver from grpc-core. But in 1.28.0 DnsNameResolver was final. Downgrades are very likely to cause breakages.

To fix the version problem(s) (there’s several), move the io.grpc dependencies to the end bump their versions to 1.29.0.

      <dependencies>
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>google-cloud-firestore</artifactId>
            <version>1.34.0</version>
        </dependency>
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>google-cloud-storage</artifactId>
            <version>1.108.0</version>
        </dependency>
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>google-cloud-pubsub</artifactId>
            <version>1.106.0</version>
        </dependency>
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>google-cloud-compute</artifactId>
            <version>0.118.0-alpha</version>
        </dependency>
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>google-cloud-vision</artifactId>
            <version>1.99.3</version>
        </dependency>
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>google-cloud-translate</artifactId>
            <version>1.94.5</version>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-netty-shaded</artifactId>
            <version>1.29.0</version>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-protobuf</artifactId>
            <version>1.29.0</version>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-stub</artifactId>
            <version>1.29.0</version>
        </dependency>
    </dependencies>

Maven has poor transitive dependency resolution, and happily downgrades packages without any warning. It is good practice to use maven-enforcer’s requireUpperBoundDeps to detect issues like this:

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-enforcer-plugin</artifactId>
        <version>1.4.1</version>
        <executions>
          <execution>
            <id>enforce</id>
            <goals>
              <goal>enforce</goal>
            </goals>
            <configuration>
              <rules>
                <requireUpperBoundDeps/>
              </rules>
            </configuration>
          </execution>
        </executions>
      </plugin>

With your broken dependencies, it would have noticed the downgrades:

[WARNING] Rule 0: org.apache.maven.plugins.enforcer.RequireUpperBoundDeps failed with message:
Failed while enforcing RequireUpperBoundDeps. The error(s) are [
Require upper bound dependencies error for io.grpc:grpc-netty-shaded:1.28.0 paths to dependency are:
+-com.example:examples:1.0.0
  +-io.grpc:grpc-netty-shaded:1.28.0
and
+-com.example:examples:1.0.0
  +-com.google.cloud:google-cloud-firestore:1.34.0
    +-io.grpc:grpc-netty-shaded:1.29.0
, 
Require upper bound dependencies error for io.grpc:grpc-protobuf:1.28.0 paths to dependency are:
+-com.example:examples:1.0.0
  +-io.grpc:grpc-protobuf:1.28.0
and
+-com.example:examples:1.0.0
  +-com.google.cloud:google-cloud-firestore:1.34.0
    +-io.grpc:grpc-protobuf:1.29.0
and
+-com.example:examples:1.0.0
  +-com.google.cloud:google-cloud-pubsub:1.106.0
    +-io.grpc:grpc-protobuf:1.29.0
...

Leave a Reply

Your email address will not be published. Required fields are marked *