apache/druid · error · IllegalStateException

Class [ ] does not implement

Error message

Class [%s] does not implement %s

What it means

DruidInjectorBuilder.addClass validates that the supplied Class implements com.google.inject.Module; if not, instantiation is impossible in the injector pipeline and an ISE is thrown naming the class and required interface.

Solutions

  1. Make the class implement Module (or extend DruidModule)
  2. Register a different class that actually implements Module
  3. If the class is a plain binding target, add it inside a module's configure() instead of addInput

Example fix

// before
builder.addClass(MyConfig.class); // not a Module
// after
builder.addClass(MyConfigModule.class); // implements DruidModule
Defensive patterns

Strategy: type-guard

Validate before calling

if (!Module.class.isAssignableFrom(clazz)) {
  throw new IllegalArgumentException(clazz + " does not implement Module");
}

Type guard

static boolean isModuleClass(Class<?> c) {
  return Module.class.isAssignableFrom(c);
}

Try / catch

try {
  builder.addClass(clazz);
} catch (IllegalStateException e) {
  if (e.getMessage().contains("does not implement")) {
    log.error("Class " + clazz + " must implement Module");
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling addInput(SomeClass.class) (leading to addClass) where SomeClass does not implement Module; addInput is its caller in the builder chain.

Common situations: Typos passing the wrong class (a config class instead of a module); refactors removing `implements Module` from a class still registered in initialization lists; tests registering non-module classes.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at server/src/main/java/org/apache/druid/guice/DruidInjectorBuilder.java:174

    return this;
  }

  public DruidInjectorBuilder addClass(Class<?> input)
  {
    if (!acceptModule(input)) {
      return this;
    }
    if (DruidModule.class.isAssignableFrom(input)) {
      @SuppressWarnings("unchecked")
      DruidModule module = baseInjector.getInstance((Class<? extends DruidModule>) input);
      registerJacksonModules(module);
      modules.add(module);
    } else if (Module.class.isAssignableFrom(input)) {
      @SuppressWarnings("unchecked")
      Module module = baseInjector.getInstance((Class<? extends Module>) input);
      modules.add(module);
    } else {
      throw new ISE("Class [%s] does not implement %s", input, Module.class);
    }
    return this;
  }

  /**
   * Filter module classes based on the (optional) module exclude list and
   * (optional) set of known node roles.
   */
  private boolean acceptModule(Class<?> moduleClass)
  {
    // Modules config is optional: it won't be present in tests or clients.
    String moduleClassName = moduleClass.getName();
    if (moduleClassName != null && modulesConfig.getExcludeList().contains(moduleClassName)) {
      log.info("Not loading module %s because it is present in excludeList", moduleClassName);
      return false;
    }

    // Tests don't have node roles, and so want to load the given modules

View on GitHub (pinned to 9b90983fd2)