apache/druid · warning
Expected [ ] found [ ]. Unknown class for context factory…
Error message
Expected [%s] found [%s]. Unknown class for context factory. Not logging shutdown
What it means
Log4jShutterDownerModule registers a graceful log4j shutdown hook during Guice configuration. If the installed SLF4J/log4j binding provides a LoggerContextFactory that is not Log4jContextFactory, the module cannot install the shutdown registry and warns that shutdown logging will be skipped. This is a guard against running under an unexpected or custom log4j provider.
Solutions
- Ensure log4j-core is on the classpath and that no log4j-to-slf4j or other provider jar replaces the default Log4jContextFactory
- Remove conflicting logging bindings (e.g. slf4j-log4j12, logback-classic) so log4j-slf4j-impl + log4j-core are used
- If a custom LoggerContextFactory is intentional, accept the warning or patch the module to support it
Example fix
// before (pom.xml) <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-to-slf4j</artifactId> </dependency> // after <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> </dependency>
Defensive patterns
Strategy: validation
Validate before calling
Class.forName("org.apache.logging.log4j.core.impl.Log4jContextFactory", false, getClass().getClassLoader()); Type guard
boolean isLog4jCoreOnClasspath() { try { Class.forName("org.apache.logging.log4j.core.impl.Log4jContextFactory", false, Thread.currentThread().getContextClassLoader()); return true; } catch (ClassNotFoundException e) { return false; } } Prevention
- Ship log4j-slf4j-impl and log4j-core together in deployments
- Audit runtime classpath for competing SLF4J providers
- Check startup logs for logging-module warnings after any dependency change
When it happens
Trigger: Guice configure() runs at startup while LogManager.getFactory() returns a factory that is not an instance of org.apache.logging.log4j.core.impl.Log4jContextFactory — e.g. a custom or third-party LoggerContextFactory, a stripped log4j-core jar, or a different provider (slf4j-simple, logback bridge) exposing log4j API.
Common situations: Deploying Druid with a custom logging setup, shading or excluding log4j-core, using a log4j-to-slf4j bridge, or accidentally including multiple logging bindings so a non-default factory wins.
Understand the failure class
Background: "X is not installed. Please install it with pip install Y": missing optional dependency errors — ImportError/ValueError raised when a library's optional extra was never installed — this error's family across 22 libraries.
Related errors
- Log4j shutdown was registered in lifecycle but no shutdown…
- Not registering log4j shutdown hooks. Not using log4j?
- Shutdown callback registry expected class
- Cannot load JDBC driver class
- Cannot load resource
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/861f93edb3d397c0.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/main/java/org/apache/druid/initialization/Log4jShutterDownerModule.java:60
public void configure(Binder binder)
{
// Instantiate eagerly so that we get everything registered and put into the Lifecycle as early as possible
// Lifecycle scope is INIT to ensure stop runs in the last phase of lifecycle stop.
try {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
if (loader == null) {
loader = getClass().getClassLoader();
}
// Reflection to try and allow non Log4j2 stuff to run. This acts as a gateway to stop errors in the next few lines
// In log4j api
Class.forName("org.apache.logging.log4j.LogManager", false, loader);
// In log4j core
Class.forName("org.apache.logging.log4j.core.util.ShutdownCallbackRegistry", false, loader);
final LoggerContextFactory contextFactory = LogManager.getFactory();
if (!(contextFactory instanceof Log4jContextFactory)) {
log.warn(
"Expected [%s] found [%s]. Unknown class for context factory. Not logging shutdown",
Log4jContextFactory.class.getName(),
contextFactory.getClass().getName()
);
return;
}
final ShutdownCallbackRegistry registry = ((Log4jContextFactory) contextFactory).getShutdownCallbackRegistry();
if (!(registry instanceof Log4jShutdown)) {
log.warn(
"Shutdown callback registry expected class [%s] found [%s]. Skipping shutdown registry",
Log4jShutdown.class.getName(),
registry.getClass().getName()
);
return;
}
binder.bind(Log4jShutdown.class).toInstance((Log4jShutdown) registry);
binder.bind(Key.get(Log4jShutterDowner.class, Names.named("ForTheEagerness")))
.to(Log4jShutterDowner.class)View on GitHub (pinned to 9b90983fd2)