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
- Ensure MasterServletFilter is declared/registered exactly once in the web application
- If redeploying, ensure the old webapp classloader is discarded so the static instance is released (full restart if needed)
- 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
- Register the filter exactly once (single mapping in web.xml)
- Perform full server restarts instead of partial hot redeploys
- In tests, reset the static instance between tests
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;
}
@VisibleForTestingView on GitHub (pinned to 184c821202)