[GR-59060] [Native Image] Fatal error: com.oracle.svm.core.util.VMError$HostedError: guarantee failed when including java agent (DataDog)
Describe the Issue
HI! I am in the process of migrating an existing spring boot application to Graalvm. One of the requirements is to instrument the application with the Datadog agent, which, according to the documentation (https://docs.datadoghq.com/tracing/trace_collection/compatibility/java/?tab=graalvm#graalvm-native-image-support) is GraalVM compatible.
However when compiling the native image by using the native-maven-plugin I get the following error
Fatal error: com.oracle.svm.core.util.VMError$HostedError: guarantee failed
at org.graalvm.nativeimage.builder/com.oracle.svm.core.util.VMError.shouldNotReachHere(VMError.java:72)
Note that if I used the Liberica Native Image Kit then the compilation succeeds. I have stripped down my project and found out that the error is triggered when including the datadog tracing agent and the java library Redisson (https://github.com/redisson/redisson). If I exclude one of the two dependencies, then the compilation process works fine. Thanks for the support!
Using the latest version of GraalVM can resolve many issues.
- [x] I tried with the latest version of GraalVM.
GraalVM Version
java 17.0.12 2024-07-16 LTS Java(TM) SE Runtime Environment Oracle GraalVM 17.0.12+8.1 (build 17.0.12+8-LTS-jvmci-23.0-b41) Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 17.0.12+8.1 (build 17.0.12+8-LTS-jvmci-23.0-b41, mixed mode, sharing)
Operating System and Version
Darwin Kernel Version 23.6.0: Mon Jul 29 21:14:30 PDT 2024; root:xnu-10063.141.2~1/RELEASE_ARM64_T6000 arm64
Build Command
./mvnw -e clean native:compile -Pnative
Expected Behavior
I would expect the compilation process to succeed and generate a native image of my repo
Actual Behavior
The compilation fails at the step [2/8] Performing analysis
Steps to Reproduce
git clone https://github.com/matteoluzzi/spring-boot-native-redisson.git./mvnw -e clean native:compile -Pnative
Additional Context
I have tried to build the native image with metadata generated by the graavm tracing agent by passing the -H:DynamicProxyConfigurationFiles, -H:ReflectionConfigurationFiles, -H:ResourceConfigurationFile, -H:JNIConfigurationFiles and -H:SerializationConfigurationFiles, but getting the same error. I have included the generated *.json files in the sample project so it's possible to pass them to the build process by adding a <buildArg> at https://github.com/matteoluzzi/spring-boot-native-redisson/blob/main/pom.xml#L49
Build Log Output and Error Messages
[2/8] Performing analysis... [] (20.2s @ 2.10GB)
15,913 (83.25%) of 19,114 types reachable
25,524 (53.79%) of 47,451 fields reachable
87,336 (57.75%) of 151,236 methods reachable
5,604 types, 480 fields, and 13,037 methods registered for reflection
1 native library: -framework CoreServices
Fatal error: com.oracle.svm.core.util.VMError$HostedError: guarantee failed
at org.graalvm.nativeimage.builder/com.oracle.svm.core.util.VMError.shouldNotReachHere(VMError.java:72)
at org.graalvm.nativeimage.builder/com.oracle.svm.core.util.VMError.guarantee(VMError.java:86)
at org.graalvm.nativeimage.builder/com.oracle.svm.core.hub.ClassForNameSupport.registerClass(ClassForNameSupport.java:63)
at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.reflect.ReflectionDataBuilder.registerTypesForGenericSignature(ReflectionDataBuilder.java:726)
at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.reflect.ReflectionDataBuilder.registerTypesForGenericSignature(ReflectionDataBuilder.java:683)
at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.reflect.ReflectionDataBuilder.registerTypesForGenericSignature(ReflectionDataBuilder.java:677)
at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.reflect.ReflectionDataBuilder.registerTypesForClass(ReflectionDataBuilder.java:564)
at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.reflect.ReflectionDataBuilder.registerHeapDynamicHub(ReflectionDataBuilder.java:969)
at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.heap.SVMImageHeapScanner.onObjectReachable(SVMImageHeapScanner.java:155)
at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.heap.ImageHeapScanner.lambda$createImageHeapObject$5(ImageHeapScanner.java:396)
at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.heap.ImageHeapScanner.lambda$postTask$14(ImageHeapScanner.java:759)
at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.util.CompletionExecutor.executeCommand(CompletionExecutor.java:187)
at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.util.CompletionExecutor.lambda$executeService$0(CompletionExecutor.java:171)
at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1395)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)
Hi @matteoluzzi,
Thank you for reaching out to us about this. We'll take a look into this shortly and I'll make sure to keep you updated.
I was able to reproduce your issue. We will take a closer look into this and I'll keep you updated.
Note that if I used the Liberica Native Image Kit then the compilation succeeds.
While the compilation might succeed in this case, I doubt that the underlying issue is fixed there. The error you see originates in this line: https://github.com/oracle/graal/blob/0ab0b8ee4f1e6e17156f91a9897c061512cb2a9f/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/ClassForNameSupport.java#L63 Maybe in their version this check is patched out or the configuration metadata that gets used in that image build is different (thus preventing the registration to happen in the first place).
This VMError.guarantee(...) is what fails, if you try to register a fully-qualified classname for NI Class.forName-support with two different class objects. This can only happen if two different classes with the equal fully-qualified classname were loaded by two different classloader at image-builtime.
That is currently a fundamental limitation of native-image compared to regular Java. So far we are not able to lookup classnames at runtime from different classloaders. I.e. in the image there is only a single map from fully-qualified classname to class instance. If there are two different class objects with the same fully-qualified classname we cannot handle it.
For more info see WIP PR: https://github.com/oracle/graal/pull/9893
Hi @olpaw, thanks for looking at this issue and explaining what is causing the error. From what I understood, both the Datadog agent and the Redisson library are registering the same fully qualified classname. Could it be possible to get which class is causing issue by adding some logs perhaps? As a workaround for my project, I noticed that if I swap the Redisson library for a spring data redis module I can at least compile my simplified project. Does that mean that I won't occur into the same issue at runtime?
Thanks again for the help!
@matteoluzzi A suggestion in the meantime would be to use the micrometer with opentelemetry to send the data to datadog, remembering that javaagent generally has a negative impact on performance, when I used opentelemetry javaagent for example there was an average of 20% fewer requests processed in my applications used. micrometer with opentelemetry allows native compilation without major problems and also brings a gain in terms of memory and cpu usage compared to javaagent, of course the ideal is to do the test and validate that everything is needed is available in this module.
From what I understand above, this is not something Native Image can solve. Closing for now.