{"record":{"id":"50178116e8c0f426","repo":"spring-projects/spring-security","slug":"the-filterchainproxy-contains-two-filter-chains-us-501781","errorCode":null,"errorMessage":"The FilterChainProxy contains two filter chains using the matcher {requestMatcher}. If you are using multiple <http> namespace elements, you must use a 'pattern' attribute to define the request patterns to which they apply.","messagePattern":"The FilterChainProxy contains two filter chains using the matcher (.+?)\\. If you are using multiple <http> namespace elements, you must use a 'pattern' attribute to define the request patterns to which they apply\\.","errorType":"exception","errorClass":"UnreachableFilterChainException","httpStatus":null,"severity":"error","filePath":"config/src/main/java/org/springframework/security/config/http/DefaultFilterChainValidator.java","lineNumber":104,"sourceCode":"\t\twhile (chains.hasNext()) {\n\t\t\tif (chains.next() instanceof DefaultSecurityFilterChain securityFilterChain) {\n\t\t\t\tif (AnyRequestMatcher.INSTANCE.equals(securityFilterChain.getRequestMatcher()) && chains.hasNext()) {\n\t\t\t\t\tthrow new UnreachableFilterChainException(\"A universal match pattern ('/**') is defined \"\n\t\t\t\t\t\t\t+ \" before other patterns in the filter chain, causing them to be ignored. Please check the \"\n\t\t\t\t\t\t\t+ \"ordering in your <security:http> namespace or FilterChainProxy bean configuration\",\n\t\t\t\t\t\t\tsecurityFilterChain, chains.next());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void checkForDuplicateMatchers(List<SecurityFilterChain> chains) {\n\t\tDefaultSecurityFilterChain filterChain = null;\n\t\tfor (SecurityFilterChain chain : chains) {\n\t\t\tif (filterChain != null) {\n\t\t\t\tif (chain instanceof DefaultSecurityFilterChain defaultChain) {\n\t\t\t\t\tif (defaultChain.getRequestMatcher().equals(filterChain.getRequestMatcher())) {\n\t\t\t\t\t\tthrow new UnreachableFilterChainException(\n\t\t\t\t\t\t\t\t\"The FilterChainProxy contains two filter chains using the\" + \" matcher \"\n\t\t\t\t\t\t\t\t\t\t+ defaultChain.getRequestMatcher()\n\t\t\t\t\t\t\t\t\t\t+ \". If you are using multiple <http> namespace \"\n\t\t\t\t\t\t\t\t\t\t+ \"elements, you must use a 'pattern' attribute to define the request patterns to which they apply.\",\n\t\t\t\t\t\t\t\tdefaultChain, chain);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (chain instanceof DefaultSecurityFilterChain defaultChain) {\n\t\t\t\tfilterChain = defaultChain;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void checkAuthorizationFilters(List<SecurityFilterChain> chains) {\n\t\tFilter authorizationFilter = null;\n\t\tFilter filterSecurityInterceptor = null;\n\t\tfor (SecurityFilterChain chain : chains) {","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/config/src/main/java/org/springframework/security/config/http/DefaultFilterChainValidator.java#L86-L122","documentation":"DefaultFilterChainValidator.checkForDuplicateMatchers walks adjacent filter chains and throws UnreachableFilterChainException when two consecutive DefaultSecurityFilterChain instances use an equal RequestMatcher, because the second chain can never be reached. The message directs users of multiple <http> elements to differentiate them with distinct pattern attributes.","triggerScenarios":"Two adjacent SecurityFilterChains return equal RequestMatchers from getRequestMatcher() — e.g. two <http> elements both with pattern=\"/foo/**\" (or both defaulting to /**), or two programmatically registered chains built from the same matcher instance/equal matcher.","commonSituations":"Copy-pasting an <http> block and forgetting to change its pattern attribute; duplicate chain registrations during configuration refactoring; generating <http> entries from a loop/template with a repeated pattern value.","solutions":["Change the pattern attribute (or RequestMatcher) of the duplicate chain so each chain matches a distinct request set","Delete the redundant duplicate chain if it is not needed","Verify every <http> element in multi-http configurations has a unique, non-overlapping pattern","Use distinct request matchers (e.g. different AntPathRequestMatcher paths or method+path combinations) in programmatic setups"],"exampleFix":"// before\n<http pattern=\"/api/**\" security=\"none\"/>\n<http pattern=\"/api/**\" ...>...</http>\n// after\n<http pattern=\"/api/public/**\" security=\"none\"/>\n<http pattern=\"/api/**\" ...>...</http>","handlingStrategy":"validation","validationCode":"java.util.Set<RequestMatcher> seen = new java.util.HashSet<>();\nfor (SecurityFilterChain c : chains) {\n    if (!seen.add(((DefaultSecurityFilterChain) c).getRequestMatcher())) throw new IllegalStateException(\"Duplicate matcher: \" + c);\n}","typeGuard":null,"tryCatchPattern":"try {\n    filterChainProxy.afterPropertiesSet();\n} catch (UnreachableFilterChainException e) {\n    logger.error(\"Duplicate chain matcher: {}\", e.getMessage());\n}","preventionTips":["Give every <http> element a unique pattern attribute","Grep generated/template XML for repeated pattern values","Differentiate chains by path and HTTP method matchers"],"tags":["spring-security","filter-chain","duplicate-config","startup-validation"],"backgroundTag":"conflicting-config-options","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}