SonarSource/sonarqube · error · IllegalStateException

Modules should be added as instances

Error message

Modules should be added as instances

What it means

SpringComponentContainer.add() throws this IllegalStateException when a Module is passed as a Class instead of an instance. Modules must be configured (module.configure(this) is invoked on instances); registering a Module class as a bean type would skip configuration and silently register it as a component instead, so the container rejects the pattern outright.

Source

Thrown at sonar-core/src/main/java/org/sonar/core/platform/SpringComponentContainer.java:102

    add(new StartableBeanPostProcessor());
    add(externalExtensions);
    add(propertyDefs);
  }

  /**
   * Beans need to have a unique name, otherwise they'll override each other.
   * The strategy is:
   * - For classes, use the classloader + fully qualified class name as the name of the bean
   * - For instances, use the Classloader + FQCN + toString()
   * - If the object is a collection, iterate through the elements and apply the same strategy for each of them
   */
  @Override
  public Container add(Object... objects) {
    for (Object o : objects) {
      if (o instanceof Class) {
        Class<?> clazz = (Class<?>) o;
        if (Module.class.isAssignableFrom(clazz)) {
          throw new IllegalStateException("Modules should be added as instances");
        }
        context.registerBean(componentKeys.ofClass(clazz), clazz);
        declareExtension("", o);
      } else if (o instanceof Module module) {
        module.configure(this);
      } else if (o instanceof Iterable) {
        add(Iterables.toArray((Iterable<?>) o, Object.class));
      } else {
        registerInstance(o);
        declareExtension("", o);
      }
    }
    return this;
  }

  @Override
  public void addWebApiV2ConfigurationClass(Class<?> clazz) {
    webConfigurationClasses.add(clazz);

View on GitHub (pinned to 184c821202)

Solutions

  1. Pass a Module instance instead of the class: container.add(new MyModule()).
  2. Only pass Class objects for components that are not Modules (beans to be instantiated by the container).
  3. If the class genuinely should not be a Module, remove the 'implements Module' declaration.

Example fix

// before
container.add(CoreModule.class);
// after
container.add(new CoreModule());
Defensive patterns

Strategy: type-guard

Validate before calling

void safeAdd(SpringComponentContainer container, Object... objects) {
  for (Object o : objects) {
    if (o instanceof Class<?> clazz && Module.class.isAssignableFrom(clazz)) {
      throw new IllegalArgumentException("Pass Module instances, not classes: " + clazz.getName());
    }
  }
  container.add(objects);
}

Type guard

boolean isModuleClass(Object o) {
  return o instanceof Class<?> clazz && Module.class.isAssignableFrom(clazz); // never pass these to add()
}

Try / catch

try {
  container.add(x);
} catch (IllegalStateException e) {
  // 'Modules should be added as instances': replace x with new X()
}

Prevention

When it happens

Trigger: Calling container.add(SomeModule.class) where SomeModule implements Module (directly or via subclass) — the Class branch detects Module.class.isAssignableFrom(clazz) and throws.

Common situations: Copy-pasting a component registration line and accidentally passing a Module subclass's class literal instead of 'new SomeModule()'; switching from add(new X()) to add(X.class) for a Module.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09). Data as JSON: /api/errors/4b6b4a9b9c32ecb9. Report an issue: GitHub.