SonarSource/sonarqube · error · IllegalStateException
Multiple redirects have been found for
Error message
Multiple redirects have been found for '%s'
What it means
RedirectFilter resolves the request path against a set of registered Redirect rules and applies exactly one redirect. If more than one rule matches the same path, the filter cannot choose deterministically and throws this IllegalStateException in doFilter's default branch.
Solutions
- Find the colliding Redirect registrations and make their 'from' matchers mutually exclusive (narrow one pattern)
- Remove or rename the plugin-registered redirect that duplicates a core redirect path
- Log all registered redirect rules at startup to detect overlapping patterns before runtime
Example fix
// before
Redirect newSimpleRedirect("/doc", "/documentation");
Redirect newSimpleRedirect("/doc/*", "/documentation/*"); // both match /doc/x
// after
Redirect newSimpleRedirect("/doc", "/documentation");
Redirect newSimpleRedirect("/doc/**", "/documentation/**"); // mutually exclusive patterns Defensive patterns
Strategy: validation
Validate before calling
Map<String, Long> hits = redirects.stream().collect(Collectors.groupingBy(r -> r.from, Collectors.counting()));
List<String> dupes = hits.entrySet().stream().filter(e -> e.getValue() > 1).map(Map.Entry::getKey).toList();
if (!dupes.isEmpty()) throw new IllegalStateException("Overlapping redirects registered for: " + dupes); Try / catch
try { chain.doFilter(req, res); } catch (IllegalStateException e) { if (e.getMessage().startsWith("Multiple redirects have been found for")) { log.error("Fix colliding redirect registrations for path " + path); } throw e; } Prevention
- Keep redirect 'from' patterns mutually exclusive when registering Redirect rules
- Audit plugin-registered redirects against core redirects at startup
- Prefer exact-match redirect registration over broad prefixes that can overlap
When it happens
Trigger: Two or more Redirect registrations whose matchers both match the incoming request path; doFilter then finds redirects.size() > 1.
Common situations: A plugin registering a redirect that collides with a built-in redirect (same 'from' path); overlapping glob/prefix matchers after adding a new redirect rule; duplicate registration of similar paths (e.g. '/doc' and '/doc/*').
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Missing HTTP header 'Location' in redirect of
- Unsupported protocol in redirect of
- Connection to Azure marketplace failed. Details
- Could not parse GitLab answer when creating a project…
- Could not validate GitLab write permission. Got an…
AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09).
Data as JSON: /api/errors/63cd98268401960d.
Report an issue: GitHub.
Appendix: source
Thrown at server/sonar-webserver/src/main/java/org/sonar/server/platform/web/RedirectFilter.java:62
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
String path = extractPath(request);
Predicate<Redirect> match = redirect -> redirect.test(path);
List<Redirect> redirects = REDIRECTS.stream()
.filter(match)
.toList();
switch (redirects.size()) {
case 0:
chain.doFilter(request, response);
break;
case 1:
response.sendRedirect(redirects.get(0).apply(request));
break;
default:
throw new IllegalStateException(format("Multiple redirects have been found for '%s'", path));
}
}
public static Redirect newSimpleRedirect(String from, String to) {
return new Redirect() {
@Override
public boolean test(String path) {
return from.equals(path);
}
@Override
public String apply(HttpServletRequest request) {
return format("%s%s", request.getContextPath(), to);
}
};
}
@OverrideView on GitHub (pinned to 184c821202)