spring-projects/spring-security · error · UnreachableFilterChainException
A universal match pattern ('/**') is defined before other…
Error message
A universal match pattern ('/**') is defined before other patterns in the filter chain, causing them to be ignored. Please check the ordering in your <security:http> namespace or FilterChainProxy bean configuration What it means
DefaultFilterChainValidator.checkPathOrder validates the FilterChainProxy's chain list after startup. A DefaultSecurityFilterChain whose RequestMatcher is the universal matcher (/**) placed before other chains makes all following chains unreachable, so the validator throws UnreachableFilterChainException to fail fast instead of silently ignoring those chains.
Solutions
- Move the universal-match ('/**' or anyRequest()) chain to the END of the chain list
- Put more specific patterns (e.g. /api/**, /admin/**) before the universal pattern in the XML or builder
- In programmatic config, order SecurityFilterChain beans with @Order or by registration order so /** is last
Example fix
// before <http pattern="/**" .../> <http pattern="/api/**" .../> // after <http pattern="/api/**" .../> <http pattern="/**" .../>
Defensive patterns
Strategy: validation
Validate before calling
List<String> patterns = chains.stream().map(SecurityFilterChain::toString).toList();
int universalIdx = patterns.indexOf("/**"); // or track matchers
if (universalIdx != -1 && universalIdx < patterns.size() - 1) throw new IllegalStateException("/** chain must be last"); Try / catch
try {
filterChainProxy.afterPropertiesSet();
} catch (UnreachableFilterChainException e) {
logger.error("Reorder chains: {} (unreachable: {})", e.getMessage(), e.getSecond());
} Prevention
- Always declare the /** or anyRequest() chain last
- Use @Order on programmatic SecurityFilterChain beans
- Add a startup check that specific patterns precede the universal one
When it happens
Trigger: filterChains contains a chain with AnyRequestMatcher.INSTANCE followed by at least one more chain — e.g. multiple <http> elements where the pattern='/**' one is declared first, or programmatic addFilterChain("/**", ...) before more specific chains.
Common situations: Appending new <http> blocks at the top of the XML instead of the end; building chains programmatically in the wrong order; Spring Boot SecurityFilterChain beans ordered so the catch-all comes first.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- The FilterChainProxy contains two filter chains using the…
- A filter chain that matches any request
- Anonymous access to the login page doesn't appear to be…
- It is not recommended to use authorizeRequests or…
- Possible error: Filters at position
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/ef4271dfc0863764.
Report an issue: GitHub.
Appendix: source
Thrown at config/src/main/java/org/springframework/security/config/http/DefaultFilterChainValidator.java:89
@Override
public void validate(FilterChainProxy fcp) {
for (SecurityFilterChain filterChain : fcp.getFilterChains()) {
checkLoginPageIsntProtected(fcp, filterChain.getFilters());
checkFilterStack(filterChain.getFilters());
}
checkPathOrder(new ArrayList<>(fcp.getFilterChains()));
checkForDuplicateMatchers(new ArrayList<>(fcp.getFilterChains()));
checkAuthorizationFilters(new ArrayList<>(fcp.getFilterChains()));
}
private void checkPathOrder(List<SecurityFilterChain> filterChains) {
// Check that the universal pattern is listed at the end, if at all
Iterator<SecurityFilterChain> chains = filterChains.iterator();
while (chains.hasNext()) {
if (chains.next() instanceof DefaultSecurityFilterChain securityFilterChain) {
if (AnyRequestMatcher.INSTANCE.equals(securityFilterChain.getRequestMatcher()) && chains.hasNext()) {
throw new UnreachableFilterChainException("A universal match pattern ('/**') is defined "
+ " before other patterns in the filter chain, causing them to be ignored. Please check the "
+ "ordering in your <security:http> namespace or FilterChainProxy bean configuration",
securityFilterChain, chains.next());
}
}
}
}
private void checkForDuplicateMatchers(List<SecurityFilterChain> chains) {
DefaultSecurityFilterChain filterChain = null;
for (SecurityFilterChain chain : chains) {
if (filterChain != null) {
if (chain instanceof DefaultSecurityFilterChain defaultChain) {
if (defaultChain.getRequestMatcher().equals(filterChain.getRequestMatcher())) {
throw new UnreachableFilterChainException(
"The FilterChainProxy contains two filter chains using the" + " matcher "
+ defaultChain.getRequestMatcher()
+ ". If you are using multiple <http> namespace "View on GitHub (pinned to 96852e8860)