apache/druid · warning

Shutdown callback registry expected class

Error message

Shutdown callback registry expected class [%s] found [%s]. Skipping shutdown registry

What it means

After confirming a Log4jContextFactory, the module asks it for its ShutdownCallbackRegistry and requires it to be Druid's Log4jShutdown class to hook lifecycle-managed shutdown. If log4j was configured with a custom shutdownCallbackRegistry, the default registry type is returned instead, so Druid skips installing its shutdown hooks and warns.

Solutions

  1. Remove any log4j2.shutdownCallbackRegistry / log4j.shutdownCallbackRegistry property from log4j2.component.properties or system properties so log4j uses Druid's Log4jShutdown
  2. Check the classpath for duplicate log4j-core jars that may carry a different default registry
  3. Align Druid server module and extension versions so the Log4jShutdown class matches the one log4j loads

Example fix

// before: log4j2.component.properties
log4j.shutdownCallbackRegistry=com.example.MyShutdownRegistry
// after
(property removed, letting Druid's Log4jShutdown be the registry)
Defensive patterns

Strategy: validation

Validate before calling

final String reg = System.getProperty("log4j.shutdownCallbackRegistry", System.getenv("LOG4J_SHUTDOWN_CALLBACK_REGISTRY") != null ? System.getenv("LOG4J_SHUTDOWN_CALLBACK_REGISTRY") : "org.apache.druid.server.logging.Log4jShutdown"); boolean ok = reg.endsWith("Log4jShutdown");

Prevention

When it happens

Trigger: configure() calls ((Log4jContextFactory) contextFactory).getShutdownCallbackRegistry() and the registry is not a Log4jShutdown — caused by setting the log4j2 system property log4j.shutdownCallbackRegistry to a custom registry class, or bundling a library that overrides it.

Common situations: Custom log4j2.component.properties shipping ShutdownCallbackRegistry overrides; shaded jars embedding their own registry; mixing Druid versions whose Log4jShutdown differs from the one log4j instantiates.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/7113d7bf0e4d75f0. Report an issue: GitHub.

Appendix: source

Thrown at server/src/main/java/org/apache/druid/initialization/Log4jShutterDownerModule.java:69

      }
      // 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)
            .asEagerSingleton();
    }
    catch (ClassNotFoundException | ClassCastException | LinkageError e) {
      log.warn(e, "Not registering log4j shutdown hooks. Not using log4j?");
    }
  }


  @ManageLifecycleInit

View on GitHub (pinned to 9b90983fd2)