Search code examples
google-cloud-firestoremicronautgraalvmgraalvm-native-image

Micronaut Native Image gRPC error when using Cloud Firestore


I have a basic Micronaut application that I'm building as a native image. I'm building it with these args:

  native-image \
  --no-server \
  -H:+TraceClassInitialization \
  -H:+ReportExceptionStackTraces \
  --enable-url-protocols=http,https \
  --enable-all-security-services \
  --report-unsupported-elements-at-runtime \
  --no-fallback \
  -H:ConfigurationFileDirectories=/home/app/sample-app/agent-config-dir \
  --report-unsupported-elements-at-runtime \
  --initialize-at-build-time=org.conscrypt,com.fasterxml.jackson,javax,org.slf4j \
  -jar myapp.jar

The image builds fine and I'm able to start it, but when trying to access Firestore, I get this exception:

Message: Unsupported method of Unsafe
Path Taken: new $MailingListsApiDefinition$Intercepted([MailingListsApiService mailingListsApiService],BeanContext beanContext,Qualifier qualifier,Interceptor[] interceptors) --> new MailingListsApiServiceImpl(TokenGenerator tokenGenerator,[Firestore db],ObjectMapper objectMapper)
io.micronaut.context.exceptions.BeanInstantiationException: Error instantiating bean of type  [com.example.sampleapp.api.service.impl.MailingListsApiServiceImpl]

Message: Unsupported method of Unsafe
Path Taken: new $MailingListsApiDefinition$Intercepted([MailingListsApiService mailingListsApiService],BeanContext beanContext,Qualifier qualifier,Interceptor[] interceptors) --> new MailingListsApiServiceImpl(TokenGenerator tokenGenerator,[Firestore db],ObjectMapper objectMapper)
    at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1916)
    at io.micronaut.context.DefaultBeanContext.getScopedBeanForDefinition(DefaultBeanContext.java:2383)
    at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:2298)
    at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:2270)
    at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:1240)
    at io.micronaut.context.AbstractBeanDefinition.getBeanForConstructorArgument(AbstractBeanDefinition.java:1013)
    at com.example.sampleapp.api.service.impl.$MailingListsApiServiceImplDefinition.build(Unknown Source)
    at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1889)
    at io.micronaut.context.DefaultBeanContext.createAndRegisterSingletonInternal(DefaultBeanContext.java:2635)
    at io.micronaut.context.DefaultBeanContext.createAndRegisterSingleton(DefaultBeanContext.java:2621)
    at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:2296)
    at io.micronaut.context.DefaultBeanContext.getBeanInternal(DefaultBeanContext.java:2270)
    at io.micronaut.context.DefaultBeanContext.getBean(DefaultBeanContext.java:1240)
    at io.micronaut.context.AbstractBeanDefinition.getBeanForConstructorArgument(AbstractBeanDefinition.java:1013)
    at com.example.sampleapp.api.$$MailingListsApiDefinition$InterceptedDefinition.build(Unknown Source)
    at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1889)
    at io.micronaut.context.DefaultBeanContext.getScopedBeanForDefinition(DefaultBeanContext.java:2383)
    at io.micronaut.context.DefaultBeanContext.getBeanForDefinition(DefaultBeanContext.java:2298)
    at io.micronaut.context.DefaultBeanContext.access$100(DefaultBeanContext.java:78)
    at io.micronaut.context.DefaultBeanContext$4.getTarget(DefaultBeanContext.java:426)
    at io.micronaut.context.DefaultBeanContext$4.invoke(DefaultBeanContext.java:469)
    at io.micronaut.web.router.AbstractRouteMatch.execute(AbstractRouteMatch.java:312)
    at io.micronaut.web.router.RouteMatch.execute(RouteMatch.java:118)
    at io.micronaut.http.server.netty.RoutingInBoundHandler.lambda$buildResultEmitter$9(RoutingInBoundHandler.java:1352)
    at io.reactivex.internal.operators.flowable.FlowableDefer.subscribeActual(FlowableDefer.java:35)
    at io.reactivex.Flowable.subscribe(Flowable.java:14918)
    at io.reactivex.Flowable.subscribe(Flowable.java:14868)
    at io.micronaut.core.async.publisher.Publishers.lambda$map$3(Publishers.java:196)
    at io.micronaut.http.server.context.ServerRequestContextFilter.lambda$doFilter$0(ServerRequestContextFilter.java:62)
    at io.reactivex.internal.operators.flowable.FlowableFromPublisher.subscribeActual(FlowableFromPublisher.java:29)
    at io.reactivex.Flowable.subscribe(Flowable.java:14918)
    at io.reactivex.Flowable.subscribe(Flowable.java:14868)
    at io.micronaut.http.server.netty.RoutingInBoundHandler.lambda$buildExecutableRoute$5(RoutingInBoundHandler.java:1056)
    at io.micronaut.web.router.DefaultUriRouteMatch$1.execute(DefaultUriRouteMatch.java:80)
    at io.micronaut.web.router.RouteMatch.execute(RouteMatch.java:118)
    at io.micronaut.http.server.netty.RoutingInBoundHandler.handleRouteMatch(RoutingInBoundHandler.java:686)
    at io.micronaut.http.server.netty.RoutingInBoundHandler.channelRead0(RoutingInBoundHandler.java:548)
    at io.micronaut.http.server.netty.RoutingInBoundHandler.channelRead0(RoutingInBoundHandler.java:143)
    at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:99)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:102)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:93)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.micronaut.http.netty.stream.HttpStreamsHandler.channelRead(HttpStreamsHandler.java:197)
    at io.micronaut.http.netty.stream.HttpStreamsServerHandler.channelRead(HttpStreamsServerHandler.java:121)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
    at io.netty.handler.codec.MessageToMessageCodec.channelRead(MessageToMessageCodec.java:111)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:93)
    at io.netty.handler.codec.http.HttpServerKeepAliveHandler.channelRead(HttpServerKeepAliveHandler.java:64)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.handler.flow.FlowControlHandler.dequeue(FlowControlHandler.java:191)
    at io.netty.handler.flow.FlowControlHandler.channelRead(FlowControlHandler.java:153)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436)
    at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:321)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:295)
    at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:286)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.lang.Thread.run(Thread.java:834)
    at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:517)
    at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:193)
Caused by: com.oracle.svm.core.jdk.UnsupportedFeatureError: Unsupported method of Unsafe
    at com.oracle.svm.core.util.VMError.unsupportedFeature(VMError.java:86)
    at jdk.internal.misc.Unsafe.staticFieldOffset(Unsafe.java:230)
    at sun.misc.Unsafe.staticFieldOffset(Unsafe.java:662)
    at io.grpc.netty.shaded.io.netty.util.internal.PlatformDependent0$5.run(PlatformDependent0.java:282)
    at java.security.AccessController.doPrivileged(AccessController.java:83)
    at io.grpc.netty.shaded.io.netty.util.internal.PlatformDependent0.<clinit>(PlatformDependent0.java:267)
    at com.oracle.svm.core.hub.ClassInitializationInfo.invokeClassInitializer(ClassInitializationInfo.java:350)
    at com.oracle.svm.core.hub.ClassInitializationInfo.initialize(ClassInitializationInfo.java:270)
    at java.lang.Class.ensureInitialized(DynamicHub.java:499)
    at io.grpc.netty.shaded.io.netty.util.internal.PlatformDependent.isAndroid(PlatformDependent.java:289)
    at io.grpc.netty.shaded.io.netty.util.internal.PlatformDependent.<clinit>(PlatformDependent.java:92)
    at com.oracle.svm.core.hub.ClassInitializationInfo.invokeClassInitializer(ClassInitializationInfo.java:350)
    at com.oracle.svm.core.hub.ClassInitializationInfo.initialize(ClassInitializationInfo.java:270)
    at java.lang.Class.ensureInitialized(DynamicHub.java:499)
    at io.grpc.netty.shaded.io.netty.util.AsciiString.<init>(AsciiString.java:223)
    at io.grpc.netty.shaded.io.netty.util.AsciiString.<init>(AsciiString.java:210)
    at io.grpc.netty.shaded.io.netty.util.AsciiString.cached(AsciiString.java:1401)
    at io.grpc.netty.shaded.io.netty.util.AsciiString.<clinit>(AsciiString.java:48)
    at com.oracle.svm.core.hub.ClassInitializationInfo.invokeClassInitializer(ClassInitializationInfo.java:350)
    at com.oracle.svm.core.hub.ClassInitializationInfo.initialize(ClassInitializationInfo.java:270)
    at java.lang.Class.ensureInitialized(DynamicHub.java:499)
    at io.grpc.netty.shaded.io.grpc.netty.Utils.<clinit>(Utils.java:72)
    at com.oracle.svm.core.hub.ClassInitializationInfo.invokeClassInitializer(ClassInitializationInfo.java:350)
    at com.oracle.svm.core.hub.ClassInitializationInfo.initialize(ClassInitializationInfo.java:270)
    at java.lang.Class.ensureInitialized(DynamicHub.java:499)
    at io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder.<clinit>(NettyChannelBuilder.java:74)
    at com.oracle.svm.core.hub.ClassInitializationInfo.invokeClassInitializer(ClassInitializationInfo.java:350)
    at com.oracle.svm.core.hub.ClassInitializationInfo.initialize(ClassInitializationInfo.java:270)
    at java.lang.Class.ensureInitialized(DynamicHub.java:499)
    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:280)
    at com.google.api.gax.grpc.InstantiatingGrpcChannelProvider.access$1600(InstantiatingGrpcChannelProvider.java:71)
    at com.google.api.gax.grpc.InstantiatingGrpcChannelProvider$1.createSingleChannel(InstantiatingGrpcChannelProvider.java:210)
    at com.google.api.gax.grpc.ChannelPool.create(ChannelPool.java:72)
    at com.google.api.gax.grpc.InstantiatingGrpcChannelProvider.createChannel(InstantiatingGrpcChannelProvider.java:217)
    at com.google.api.gax.grpc.InstantiatingGrpcChannelProvider.getTransportChannel(InstantiatingGrpcChannelProvider.java:200)
    at com.google.api.gax.rpc.ClientContext.create(ClientContext.java:156)
    at com.google.api.gax.rpc.ClientContext.create(ClientContext.java:123)
    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 com.google.firebase.cloud.FirestoreClient.<init>(FirestoreClient.java:45)
    at com.google.firebase.cloud.FirestoreClient.<init>(FirestoreClient.java:29)
    at com.google.firebase.cloud.FirestoreClient$FirestoreClientService.<init>(FirestoreClient.java:95)
    at com.google.firebase.cloud.FirestoreClient.getInstance(FirestoreClient.java:85)
    at com.google.firebase.cloud.FirestoreClient.getFirestore(FirestoreClient.java:78)
    at com.google.firebase.cloud.FirestoreClient.getFirestore(FirestoreClient.java:64)
    at com.example.sampleapp.config.FirestoreConfig.db(FirestoreConfig.java:27)
    at com.example.sampleapp.config.$FirestoreConfig$Db0Definition.build(Unknown Source)
    at io.micronaut.context.DefaultBeanContext.doCreateBean(DefaultBeanContext.java:1889)
    ... 103 common frames omitted

I'm pretty new to both Micronaut and GraalVM at this point, so I'm sure that I'm overlooking something simple, but I have not been able to find much about this particular error, and the things I did find did not solve my issue.

I'm using Micronaut 2.0.1 and building a fatJar using the maven-shade-plugin, which is what I'm then running the native-image generation against.

My Firestore configuration is very simple and looks like this:

@Factory
public class FirestoreConfig {

    private static final byte[] SVC_KEY = {123, 10, 32, .......};

    @Bean
    public Firestore db() throws Exception {
        InputStream serviceAccount = new ByteArrayInputStream(SVC_KEY);
        GoogleCredentials credentials = GoogleCredentials.fromStream(serviceAccount);
        FirebaseOptions options = new FirebaseOptions.Builder()
                .setCredentials(credentials)
                .build();
        FirebaseApp.initializeApp(options);
        return FirestoreClient.getFirestore();
    }

}

Then a relevant bit where I inject this config:

@Slf4j
@Singleton
public class MailingListsApiServiceImpl extends MailingListsApiService {
    private final TokenGenerator tokenGenerator;
    private final Firestore db;
    private final ObjectMapper objectMapper;

    @Inject
    public MailingListsApiServiceImpl(
                                      TokenGenerator tokenGenerator,
                                      Firestore db,
                                      ObjectMapper objectMapper) {
        this.tokenGenerator = tokenGenerator;
        this.db = db;
        this.objectMapper = objectMapper;
    }

Firebase dependency in the pom.xml

<dependency>
  <groupId>com.google.firebase</groupId>
  <artifactId>firebase-admin</artifactId>
  <version>6.15.0</version>
</dependency>

If I remove the firebase-admin dependency and comment out the usages of Firestore, then my requests do get processed correctly, so it definitely seems to be related to that and gRPC.

Any help would be greatly appreciated!


Solution

  • It seems related to this one https://github.com/oracle/graal/issues/2694

    They have fixed similar issue for netty, but probably it requires extra PR for your library https://github.com/netty/netty/pull/10428/commits/b18122834e3688cda6edc64af694cf6b06ac6b0d