SonarSource/sonarqube · error · IllegalStateException

Servlet filter is already instantiated

Error message

Servlet filter  is already instantiated

What it means

MasterServletFilter is a servlet filter designed as a singleton: its constructor stores itself in a static volatile 'instance' field and throws IllegalStateException if an instance already exists. This protects against Tomcat (or a test harness) instantiating the filter twice.

Solutions

  1. Ensure MasterServletFilter is declared/registered exactly once in the web application
  2. If redeploying, ensure the old webapp classloader is discarded so the static instance is released (full restart if needed)
  3. In tests, reset the static instance (set to null via reflection/test hook) before constructing a new instance

Example fix

// before
<filter-class>...MasterServletFilter</filter-class>
... duplicate second <filter> with same class ...
// after
single <filter> declaration mapped once in web.xml
Defensive patterns

Strategy: type-guard

Validate before calling

if (MasterServletFilter.class.getDeclaredField("instance").get(null) != null) throw new IllegalStateException("MasterServletFilter already instantiated; do not register twice");

Type guard

boolean notYetInstantiated() throws Exception { return MasterServletFilter.class.getDeclaredField("instance").get(null) == null; }

Try / catch

try { new MasterServletFilter(); } catch (IllegalStateException e) { log.warn("Filter already active in this JVM; reusing existing instance"); }

Prevention

When it happens

Trigger: Registering MasterServletFilter more than once in web.xml or programmatically, or restarting/redeploying the webapp within the same JVM classloader lifetime so a second filter instance is constructed while the static field still holds the first.

Common situations: Duplicate <filter> mappings for the same class in web.xml; hot redeploy without classloader refresh; tests constructing the filter manually after the server already created one.

Related errors


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

Appendix: source

Thrown at server/sonar-webserver/src/main/java/org/sonar/server/platform/web/MasterServletFilter.java:61

import org.sonar.api.web.HttpFilter;
import org.sonar.server.http.JakartaHttpRequest;
import org.sonar.server.http.JakartaHttpResponse;
import org.sonar.server.platform.PlatformImpl;

/**
 * Inspired by http://stackoverflow.com/a/7592883/229031
 */
public final class MasterServletFilter implements Filter {

  private static final String SCIM_FILTER_PATH = "/api/scim/v2/";
  private static final Logger LOG = LoggerFactory.getLogger(MasterServletFilter.class);
  private static volatile MasterServletFilter instance;

  private HttpFilter[] httpFilters;

  public MasterServletFilter() {
    if (instance != null) {
      throw new IllegalStateException("Servlet filter " + getClass().getName() + " is already instantiated");
    }
    instance = this;
  }

  @Override
  public void init(FilterConfig config) {
    // Filters are already available in the container unless a database migration is required. See
    // org.sonar.server.startup.RegisterServletFilters.
    List<HttpFilter> httpFilterList = PlatformImpl.getInstance().getContainer().getComponentsByType(HttpFilter.class);
    init(httpFilterList);
  }

  @CheckForNull
  public static MasterServletFilter getInstance() {
    return instance;
  }

  @VisibleForTesting

View on GitHub (pinned to 184c821202)