spring-projects/spring-security · warning

Duplicate URL defined

Error message

Duplicate URL defined: %s. The original attribute values will be overwritten

What it means

FilterInvocationSecurityMetadataSourceParser builds a URL-to-attributes map from <intercept-url> entries. When the same URL/pattern is defined more than once, the later definition silently replaces the earlier one, so a warning is logged to surface the likely config mistake.

Solutions

  1. Remove the duplicate <intercept-url> entry and keep the single intended rule
  2. Reorder and merge access attributes into one rule per pattern
  3. Migrate to authorizeHttpRequests where duplicate matchers surface as clearer ordering-based behavior

Example fix

<!-- before -->
<intercept-url pattern="/admin/**" access="hasRole('USER')"/>
<intercept-url pattern="/admin/**" access="hasRole('ADMIN')"/>
<!-- after -->
<intercept-url pattern="/admin/**" access="hasRole('ADMIN')"/>
Defensive patterns

Strategy: validation

Validate before calling

// Parse intercept-url patterns and assert uniqueness before loading context
Set<String> seen = new HashSet<>();
for (String p : interceptUrlPatterns) {
  if (!seen.add(p)) throw new IllegalStateException("Duplicate pattern: " + p);
}

Prevention

When it happens

Trigger: Two or more <intercept-url pattern="..." access="..."/> elements with identical patterns in the same <http> block, parsed via parseInterceptUrlsForFilterInvocationRequestMap.

Common situations: Copy-pasted intercept-url rules; includes/merged XML configs redefining the same pattern; refactoring leaves duplicate patterns with conflicting access attributes.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10). Data as JSON: /api/errors/abf15f5887cd2d38. Report an issue: GitHub.

Appendix: source

Thrown at config/src/main/java/org/springframework/security/config/http/FilterInvocationSecurityMetadataSourceParser.java:184

							urlElt);
			}
			BeanMetadataElement matcher = hasMatcherRef ? new RuntimeBeanReference(matcherRef)
					: matcherType.createMatcher(parserContext, path, method, servletPath);
			BeanDefinitionBuilder attributeBuilder = BeanDefinitionBuilder.rootBeanDefinition(SecurityConfig.class);
			if (useExpressions) {
				logger.info("Creating access control expression attribute '" + access + "' for " + path);
				// The single expression will be parsed later by the
				// ExpressionBasedFilterInvocationSecurityMetadataSource
				attributeBuilder.addConstructorArgValue(new String[] { access });
				attributeBuilder.setFactoryMethod("createList");

			}
			else {
				attributeBuilder.addConstructorArgValue(access);
				attributeBuilder.setFactoryMethod("createListFromCommaDelimitedString");
			}
			if (filterInvocationDefinitionMap.containsKey(matcher)) {
				logger.warn("Duplicate URL defined: " + path + ". The original attribute values will be overwritten");
			}
			filterInvocationDefinitionMap.put(matcher, attributeBuilder.getBeanDefinition());
		}
		if (addAuthenticatedAll && filterInvocationDefinitionMap.isEmpty()) {
			BeanDefinition matcher = matcherType.createMatcher(parserContext, "/**", null);
			BeanDefinitionBuilder attributeBuilder = BeanDefinitionBuilder.rootBeanDefinition(SecurityConfig.class);
			attributeBuilder.addConstructorArgValue(new String[] { "authenticated" });
			attributeBuilder.setFactoryMethod("createList");
			filterInvocationDefinitionMap.put(matcher, attributeBuilder.getBeanDefinition());
		}
		return filterInvocationDefinitionMap;
	}

	static class DefaultWebSecurityExpressionHandlerBeanFactory
			extends GrantedAuthorityDefaultsParserUtils.AbstractGrantedAuthorityDefaultsBeanFactory {

		private DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();

View on GitHub (pinned to 96852e8860)