-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Description
I’m encountering an error while building a GraalVM native image for a Spring Boot application in multimodule setup. The error indicates that an object of type org.slf4j.helpers.SubstituteLoggerFactory is found in the image heap, but the class is not initialized at build time.
Environment:
- Spring Boot: 3.4.4
- Couchbase: 3.4.4
- Couchbase SDK: 3.6.3
- Gradle: 8.1.3
- GraalVM: 23.0.2
- Native Image Plugin: 0.10.2
- SLF4J: Forced to 2.0.17
- Logback: Forced to 1.5.18
Dependency Resolution Strategy:
I’ve explicitly managed transitive dependencies using Gradle’s resolutionStrategy to force compatible versions of Netty, SLF4J, and Logback, as shown below:
force 'io.netty:netty-common:4.1.119.Final',
'io.netty:netty-buffer:4.1.119.Final',
'io.netty:netty-transport:4.1.119.Final',
eachDependency { details ->
if (details.requested.group == 'org.slf4j') {
details.useVersion '2.0.17'
}
if (details.requested.group == 'ch.qos.logback') {
details.useVersion '1.5.18'
}
}
Build Args:
I already include a comprehensive list of --initialize-at-build-time arguments, including:
--initialize-at-build-time=org.slf4j.helpers.SubstituteLoggerFactory
--initialize-at-build-time=ch.qos.logback.classic.Logger
--initialize-at-build-time=ch.qos.logback.core.*
--initialize-at-build-time=com.fasterxml.*
--initialize-at-build-time=com.azure.core.*
...
And also runtime initializations for Netty and JDK networking classes.
Error:
Despite including --initialize-at-build-time=org.slf4j.helpers.SubstituteLoggerFactory, I still get this error mentioned below:
Build resources:
- 12.09GB of memory (75.6% of 16.00GB system memory, determined at start)
- 10 thread(s) (100.0% of 10 available processor(s), determined at start)
[2/8] Performing analysis... [] (20.0s @ 1.00GB)
15,616 reachable types (80.5% of 19,403 total)
19,996 reachable fields (60.3% of 33,162 total)
9,740 reachable methods ( 7.6% of 128,606 total)
12,766 types, 4,443 fields, and 7,520 methods registered for reflection
Fatal error: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: An object of type 'org.slf4j.helpers.SubstituteLoggerFactory' was found in the image heap. This type, however, is marked for initialization at image run time for the following reason: classes are initialized at run time by default.
This is not allowed for correctness reasons: All objects that are stored in the image heap must be initialized at build time.
You now have two options to resolve this:
-
If it is intended that objects of type 'org.slf4j.helpers.SubstituteLoggerFactory' are persisted in the image heap, add
'--initialize-at-build-time=org.slf4j.helpers.SubstituteLoggerFactory'
to the native-image arguments. Note that initializing new types can store additional objects to the heap. It is advised to check the static fields of 'org.slf4j.helpers.SubstituteLoggerFactory' to see if they are safe for build-time initialization, and that they do not contain any sensitive data that should not become part of the image.
-
If these objects should not be stored in the image heap, you can use
'--trace-object-instantiation=org.slf4j.helpers.SubstituteLoggerFactory'
What I've Tried
- Ensured consistent dependency versions: Aligned SLF4J 2.0.17, Logback 1.5.18, and Netty 4.1.119.Final to avoid transitive conflicts, using Gradle's resolutionStrategy.
- Configured build-time initialization for known problematic classes, including:
- org.slf4j.helpers.SubstituteLoggerFactory
- ch.qos.logback.*
- io.netty.resolver.dns.*
- java.net.Inet*
- However, the approach (Configured build-time initialization for known problematic classes) has become unsustainable, as the list of classes requiring --initialize-at-build-time or --initialize-at-run-time continues to grow only reactively based on errors during the native-image build. This results in ongoing conflicts between runtime and build-time initialization for common libraries (e.g., logging and networking)
- Used the GraalVM agent to generate native configuration metadata and placed the output under META-INF/native-image.
- Followed GraalVM and Spring Native documentation, including known hints, logging setup, and reflection guidance.
My Questions
- Why do classes like SubstituteLoggerFactory, ch.qos.logback.classic., java.net.InetAddress, io.netty.resolver.dns., etc., still cause runtime or build-time initialization issues despite being explicitly flagged while creating spring native image (./gradlew clean :moduleName: nativeCompile -x test)?
- Are there known compatibility issues between SLF4J 2.0.17, Logback 1.5.18, Netty (4.1.119.Final), and GraalVM 23.0.2?
- Are there any additional configuration flags, hints, or best practices required to properly configure SLF4J, Logback, and Netty and related dependencies for GraalVM native-image builds
This issue likely intersects with multiple libraries used in the GraalVM native image ecosystem. Adding here for visibility:
CCing maintainers and contributors who may provide insight:
@diroussel @astubbs @rtack @davidkarlsen @tony19
Any help or insight would be appreciated. Thanks!