Reasons Logback Throws “SimpleLoggerContext cannot be cast to LoggerContext” After Migrating to GraalVM
When a Java application migrates to GraalVM native image, one of the most confusing runtime errors developers encounter comes from the logging subsystem—especially Logback and SLF4J.

I am Tuanh.net. As of 2024, I have accumulated 8 years of experience in backend programming. I am delighted to connect and share my knowledge with everyone.
java.lang.ClassCastException: class org.slf4j.helpers.SubstituteLoggerFactory$SubstituteLoggerContext
cannot be cast to class ch.qos.logback.classic.LoggerContext
1. The Hidden Cause Behind the Error
1.1. SLF4J Service Discovery in GraalVM
META-INF/services/org.slf4j.spi.SLF4JServiceProvider
ch.qos.logback.classic.spi.LogbackServiceProvider
LogbackServiceProvider, leading SLF4J to fall back to its default stub implementation: SubstituteLoggerFactory.
LoggerContext, causing the ClassCastException.
1.2. Why “It Works in JVM but Not in GraalVM”
Logger logger = LoggerFactory.getLogger(MyApp.class);
logger.info("Application started!");
2. The Java Example and Root Analysis
2.1. Example Project Setup
package com.example.demo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
private static final Logger log = LoggerFactory.getLogger(DemoApplication.class);
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
log.info("Hello from GraalVM!");
}
}
pom.xml:
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-logging</artifactid>
</dependency>
mvn -Pnative native:compile
./target/demo
Caused by: java.lang.ClassCastException: class org.slf4j.helpers.SubstituteLoggerFactory$SubstituteLoggerContext cannot be cast to class ch.qos.logback.classic.LoggerContext
2.2. Dissecting the Stacktrace
LoggerFactory.getILoggerFactory()
→ returns SubstituteLoggerFactory
→ returns SubstituteLoggerContext
→ Logback expects LoggerContext
→ cast fails
3. Techniques to Fix the Problem
3.1. Include SLF4J Service Providers in Reflection Config
src/main/resources/META-INF/native-image/reflect-config.json:
[
{
"name": "ch.qos.logback.classic.spi.LogbackServiceProvider",
"allDeclaredConstructors": true
}
]
--initialize-at-build-time=ch.qos.logback.classic.spi.LogbackServiceProvider
native-image.properties:
Args = --report-unsupported-elements-at-runtime
--initialize-at-build-time=ch.qos.logback.classic
--initialize-at-build-time=org.slf4j.impl.StaticLoggerBinder
3.2. Add Resource Configuration
resource-config.json file to retain Logback configuration files:
{
"resources": [
{ "pattern": "logback.xml" },
{ "pattern": "logback-spring.xml" },
{ "pattern": "META-INF/services/.*" }
]
}
3.3. Verify Binding at Build Time
SLF4J: Found binding in [jar:file:/.../logback-classic-1.4.14.jar!/org/slf4j/impl/StaticLoggerBinder.class]
System.out.println("Logger Factory: " + LoggerFactory.getILoggerFactory().getClass().getName());
Logger Factory: ch.qos.logback.classic.LoggerContext
4. Extended Discussion: When the Error Persists
4.1. Mixing Multiple Logging Libraries
slf4j-simple, log4j-slf4j2-impl, etc.), GraalVM will embed multiple providers, and SLF4J might bind to the wrong one.Run this Maven command to inspect duplicates:
mvn dependency:tree | grep slf4j
slf4j-simple and logback-classic, exclude the simple logger:
<exclusion>
<groupid>org.slf4j</groupid>
<artifactid>slf4j-simple</artifactid>
</exclusion>
4.2. Spring Boot 3.x and Native Image Integration
spring-aot-maven-plugin to generate AOT metadata automatically.If you’re using it, you can inspect generated configs in:
target/generated/aotResources/META-INF/native-image
LogbackServiceProvider, so you may need to add a manual hint:
@NativeHint(
types = @TypeHint(
types = ch.qos.logback.classic.spi.LogbackServiceProvider.class,
access = AccessBits.ALL
)
)
5. Final Thoughts and Broader Perspective
5.1. Why Logging Is Tricky in Native Images
5.2. Long-Term Strategy
6. Complete Example Configuration Summary
src/
├─ main/
│ ├─ java/com/example/demo/DemoApplication.java
│ ├─ resources/
│ │ ├─ logback-spring.xml
│ │ ├─ META-INF/native-image/
│ │ │ ├─ reflect-config.json
│ │ │ └─ resource-config.json
│ │ └─ native-image.properties
[
{ "name": "ch.qos.logback.classic.spi.LogbackServiceProvider", "allDeclaredConstructors": true }
]
{
"resources": [
{ "pattern": "logback." },
{ "pattern": "META-INF/services/." }
]
}
Args = --initialize-at-build-time=ch.qos.logback.classic,org.slf4j.impl.StaticLoggerBinder
--report-unsupported-elements-at-runtime
SimpleLoggerContext cannot be cast to LoggerContext error in GraalVM is not really a Logback bug—it’s a visibility issue caused by the static world of native compilation.Once you restore Logback’s SPI visibility and preserve its configuration files, the logger works just as it does on the JVM—only faster, leaner, and ready for microservice duty.
Read more at : Reasons Logback Throws “SimpleLoggerContext cannot be cast to LoggerContext” After Migrating to GraalVM





