{"record":{"id":"ff2baa3b8373f298","repo":"spring-projects/spring-security","slug":"possible-error-filters-at-position-i-and-j-ar","errorCode":null,"errorMessage":"Possible error: Filters at position <i> and <j> are both instances of <clazz.getName()>","messagePattern":"Possible error: Filters at position <i> and <j> are both instances of <clazz\\.getName\\(\\)>","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"config/src/main/java/org/springframework/security/config/http/DefaultFilterChainValidator.java","lineNumber":179,"sourceCode":"\t\tcheckForDuplicates(BasicAuthenticationFilter.class, filters);\n\t\tcheckForDuplicates(SecurityContextHolderAwareRequestFilter.class, filters);\n\t\tcheckForDuplicates(JaasApiIntegrationFilter.class, filters);\n\t\tcheckForDuplicates(ExceptionTranslationFilter.class, filters);\n\t\tif (USING_ACCESS) {\n\t\t\tcheckForDuplicates(AccessComponents.getFilterSecurityInterceptorClass(), filters);\n\t\t}\n\t\tcheckForDuplicates(AuthorizationFilter.class, filters);\n\t}\n\n\tprivate void checkForDuplicates(Class<? extends Filter> clazz, List<Filter> filters) {\n\t\tfor (int i = 0; i < filters.size(); i++) {\n\t\t\tFilter f1 = filters.get(i);\n\t\t\tif (clazz.isAssignableFrom(f1.getClass())) {\n\t\t\t\t// Found the first one, check remaining for another\n\t\t\t\tfor (int j = i + 1; j < filters.size(); j++) {\n\t\t\t\t\tFilter f2 = filters.get(j);\n\t\t\t\t\tif (clazz.isAssignableFrom(f2.getClass())) {\n\t\t\t\t\t\tthis.logger.warn(\"Possible error: Filters at position \" + i + \" and \" + j + \" are both \"\n\t\t\t\t\t\t\t\t+ \"instances of \" + clazz.getName());\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/*\n\t * Checks for the common error of having a login page URL protected by the security\n\t * interceptor\n\t */\n\tprivate void checkLoginPageIsntProtected(FilterChainProxy fcp, List<Filter> filterStack) {\n\t\tExceptionTranslationFilter exceptions = getFilter(ExceptionTranslationFilter.class, filterStack);\n\t\tif (exceptions == null\n\t\t\t\t|| !(exceptions.getAuthenticationEntryPoint() instanceof LoginUrlAuthenticationEntryPoint)) {\n\t\t\treturn;\n\t\t}","sourceCodeStart":161,"sourceCodeEnd":197,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/config/src/main/java/org/springframework/security/config/http/DefaultFilterChainValidator.java#L161-L197","documentation":"DefaultFilterChainValidator.checkFilterStack scans the Spring Security filter chain and warns when two filters at different positions are both instances of the same configured filter class. Duplicate filters in the chain are almost always a configuration error that causes the filter to run twice (double authentication, double logging, order confusion). This is a logged warning, not an exception.","triggerScenarios":"Calling validate() on a FilterChainProxy whose security filter list contains two instances assignable to the same filter class, e.g. manually adding a filter that the namespace/DSL already registers, or declaring the same filter bean twice.","commonSituations":"Adding a custom or stock filter (e.g. UsernamePasswordAuthenticationFilter, CsrfFilter) via addFilterBefore/After when it is already in the chain; copying namespace config from XML to Java config and double-registering; multiple http blocks each adding the same filter.","solutions":["Remove the manual registration if Spring Security already inserts that filter by default.","Use addFilterBefore/addFilterAfter with a distinct custom class instead of re-registering a stock filter.","Log the full filter chain (enable debug logging for FilterChainProxy) and delete the duplicate entry.","If intentional, verify idempotency or subclass the filter so classes differ."],"exampleFix":"// before: duplicate\nhttp.addFilter(new UsernamePasswordAuthenticationFilter());\nhttp.formLogin(Customizer.withDefaults());\n// after: rely on DSL registration\nhttp.formLogin(Customizer.withDefaults());","handlingStrategy":"validation","validationCode":"// detect duplicate filter classes before enabling the chain\nSet<Class<?>> seen = new HashSet<>();\nfor (Filter f : filters) {\n    if (!seen.add(f.getClass())) {\n        throw new IllegalStateException(\"Duplicate filter: \" + f.getClass().getName());\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prefer the securityFilterChain DSL over manual addFilter for stock filters.","Review startup logs for 'Possible error: Filters at position' warnings.","Write a test asserting the exact expected filter-chain order.","When inserting filters, choose addFilterBefore/After targets that are not themselves duplicated."],"tags":["spring-security","filter-chain","configuration","duplicate"],"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-14T11:17:12.474Z"}