Search code examples
javagoogle-cloud-firestoreprotocol-buffersgrpc

maxInboundMessageSize when trying to save a protobuf object to firestore


I am using gRPC protobuf for my project and in the auth sub-module I have this piece of code:

    @Override
    public void signUp(SignUpRequest request, StreamObserver<SignUpResponse> response) {
        String email = request.getEmail();
        String password = request.getPassword();
        User user;
        long now = Instant.now().toEpochMilli();

        CreateRequest createRequest = new CreateRequest()
                .setEmail(request.getEmail())
                .setPassword(request.getPassword())
                .setEmailVerified(true);
        UserRecord userRecord;
        try {
            userRecord = FirebaseAuth.getInstance().createUserAsync(createRequest).get();
        } catch (InterruptedException e) {
            e.printStackTrace();
            response.onError(Status.INTERNAL.withDescription("User creation interrupted").asRuntimeException());
            return;
        } catch (ExecutionException e) {
            e.printStackTrace();
            response.onError(Status.INVALID_ARGUMENT.withDescription("Invalid email or password").asRuntimeException());
            return;
        }


        user = User.newBuilder()
                .setEmail(request.getEmail())
                .setCreatedAt(now)
                .setUpdatedAt(now)
                .build();
        log.info("user record"+userRecord.toString());


        try {
            String jsonString = JsonFormat.printer().print(user);
            Firestore db = FirestoreClient.getFirestore();
            DocumentReference userRef = db.collection("users").document();
            userRef.set(jsonString);
        } catch (InvalidProtocolBufferException e) {
            e.printStackTrace();
        }
        log.info(user.toString());


        SignUpResponse signUpResponse = SignUpResponse.newBuilder()
                .setUser(user)
                .setResponseTime(now)
                .setResponseStatus(200)
                .build();

        response.onNext(signUpResponse);
        response.onCompleted();
    }

As you can see I am using firebase to authenticate and trying to save the user in users collection in firestore. But I'm getting this error:

Exception in thread "pool-2-thread-2" java.lang.NoSuchFieldError: maxInboundMessageSize
    at io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder.maxInboundMessageSize(NettyChannelBuilder.java:531)
    at io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder.maxInboundMessageSize(NettyChannelBuilder.java:72)
    at com.google.api.gax.grpc.InstantiatingGrpcChannelProvider.createSingleChannel(InstantiatingGrpcChannelProvider.java:370)
    at com.google.api.gax.grpc.ChannelPool.<init>(ChannelPool.java:105)
    at com.google.api.gax.grpc.ChannelPool.create(ChannelPool.java:83)
    at com.google.api.gax.grpc.InstantiatingGrpcChannelProvider.createChannel(InstantiatingGrpcChannelProvider.java:236)
    at com.google.api.gax.grpc.InstantiatingGrpcChannelProvider.getTransportChannel(InstantiatingGrpcChannelProvider.java:230)
    at com.google.api.gax.rpc.ClientContext.create(ClientContext.java:201)
    at com.google.api.gax.rpc.ClientContext.create(ClientContext.java:132)
    at com.google.cloud.firestore.spi.v1.GrpcFirestoreRpc.<init>(GrpcFirestoreRpc.java:127)
    at com.google.cloud.firestore.FirestoreOptions$DefaultFirestoreRpcFactory.create(FirestoreOptions.java:88)
    at com.google.cloud.firestore.FirestoreOptions$DefaultFirestoreRpcFactory.create(FirestoreOptions.java:80)
    at com.google.cloud.ServiceOptions.getRpc(ServiceOptions.java:560)
    at com.google.cloud.firestore.FirestoreOptions.getFirestoreRpc(FirestoreOptions.java:358)
    at com.google.cloud.firestore.FirestoreImpl.<init>(FirestoreImpl.java:79)
    at com.google.cloud.firestore.FirestoreOptions$DefaultFirestoreFactory.create(FirestoreOptions.java:71)
    at com.google.cloud.firestore.FirestoreOptions$DefaultFirestoreFactory.create(FirestoreOptions.java:64)
    at com.google.cloud.ServiceOptions.getService(ServiceOptions.java:540)
    at com.google.firebase.cloud.FirestoreClient.<init>(FirestoreClient.java:55)
    at com.google.firebase.cloud.FirestoreClient.<init>(FirestoreClient.java:32)
    at com.google.firebase.cloud.FirestoreClient$FirestoreInstances.lambda$get$0(FirestoreClient.java:150)
    at java.base/java.util.HashMap.computeIfAbsent(HashMap.java:1220)
    at java.base/java.util.Collections$SynchronizedMap.computeIfAbsent(Collections.java:2760)
    at com.google.firebase.cloud.FirestoreClient$FirestoreInstances.get(FirestoreClient.java:150)
    at com.google.firebase.cloud.FirestoreClient.getInstance(FirestoreClient.java:121)
    at com.google.firebase.cloud.FirestoreClient.getFirestore(FirestoreClient.java:98)
    at com.google.firebase.cloud.FirestoreClient.getFirestore(FirestoreClient.java:83)
    at com.google.firebase.cloud.FirestoreClient.getFirestore(FirestoreClient.java:68)
    at server.AuthServiceImpl.signUp(AuthServiceImpl.java:83)
    at root.protos.auth.AuthServiceGrpc$MethodHandlers.invoke(AuthServiceGrpc.java:277)
    at io.grpc.stub.ServerCalls$UnaryServerCallHandler$UnaryServerCallListener.onHalfClose(ServerCalls.java:182)
    at io.grpc.PartialForwardingServerCallListener.onHalfClose(PartialForwardingServerCallListener.java:35)
    at io.grpc.ForwardingServerCallListener.onHalfClose(ForwardingServerCallListener.java:23)
    at io.grpc.ForwardingServerCallListener$SimpleForwardingServerCallListener.onHalfClose(ForwardingServerCallListener.java:40)
    at io.grpc.util.TransmitStatusRuntimeExceptionInterceptor$1.onHalfClose(TransmitStatusRuntimeExceptionInterceptor.java:74)
    at io.grpc.internal.ServerCallImpl$ServerStreamListenerImpl.halfClosed(ServerCallImpl.java:335)
    at io.grpc.internal.ServerImpl$JumpToApplicationThreadServerStreamListener$1HalfClosed.runInContext(ServerImpl.java:866)
    at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
    at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:133)

In the parent pom I have:

        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-netty</artifactId>
            <version>${grpc.version}</version>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-protobuf</artifactId>
            <version>${grpc.version}</version>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-stub</artifactId>
            <version>${grpc.version}</version>
        </dependency>
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java-util</artifactId>
            <version>${protobuf-java.version}</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java</artifactId>
            <version>${protobuf-java.version}</version>
        </dependency>

where <grpc.version>1.41.0</grpc.version> and <protobuf-java.version>3.19.0</protobuf-java.version>

Now I am not sure about the issue. Is it because firestore doesn't support proto objects or something else? And what can I do to solve the issue?


Solution

  • It looks like you are running into classloader hell.

    The field maxInboundMessageSize was local to the class NettyChannelBuilder, but as of 1.51.x that field was moved to the parent class AbstractManagedChannelImplBuilder. Probably the version of firestore you are using is pulling in a newer version of gRPC and one version is creating the object while the other version is being used for the class method logic.

    I would recommend upgrading your gRPC version to 1.53.0.