spring-projects/spring-security · error · ApplicationContextException

Bean '{name}' must be a UserDetailsService or an Authenticat

Error message

Bean '{name}' must be a UserDetailsService or an AuthenticationUserDetailsService

What it means

UserDetailsServiceFactoryBean.authenticationUserDetailsService() resolves a bean reference into a UserDetailsService wrapper for remember-me/x509 support. After the bean is fetched, it must be an AuthenticationUserDetailsService or a UserDetailsService (or CachingUserDetailsService factory product). If the referenced bean is neither, an ApplicationContextException is thrown because no UserDetails lookup strategy can be derived from it.

Source

Thrown at config/src/main/java/org/springframework/security/config/http/UserDetailsServiceFactoryBean.java:90

							+ " Please use a specific Id reference.");
				}
				return (AuthenticationUserDetailsService) beans.values().toArray()[0];
			}
			uds = getUserDetailsService();
		}
		else {
			Object bean = this.beanFactory.getBean(name);
			if (bean instanceof AuthenticationUserDetailsService) {
				return (AuthenticationUserDetailsService) bean;
			}
			else if (bean instanceof UserDetailsService) {
				uds = cachingUserDetailsService(name);
				if (uds == null) {
					uds = (UserDetailsService) bean;
				}
			}
			else {
				throw new ApplicationContextException(
						"Bean '" + name + "' must be a UserDetailsService or an" + " AuthenticationUserDetailsService");
			}
		}
		return new UserDetailsByNameServiceWrapper(uds);
	}

	/**
	 * Obtains a user details service for use in RememberMeServices etc. Will return a
	 * caching version if available so should not be used for beans which need to separate
	 * the two.
	 */
	private UserDetailsService getUserDetailsService() {
		Map<String, ?> beans = getBeansOfType(CachingUserDetailsService.class);
		if (beans.isEmpty()) {
			beans = getBeansOfType(UserDetailsService.class);
		}
		if (beans.isEmpty()) {
			throw new ApplicationContextException("No UserDetailsService registered.");

View on GitHub (pinned to 96852e8860)

Solutions

  1. Make the referenced bean implement org.springframework.security.core.userdetails.UserDetailsService (loadUserByUsername) or AuthenticationUserDetailsService.
  2. Point service-ref at an existing UserDetailsService bean instead of the wrong bean.
  3. If the bean is a CachingUserDetailsService produced by a factory, ensure the factory-bean type is correctly declared so it is recognized as a UserDetailsService.

Example fix

// before
<bean id="userService" class="com.app.UserService"/>
<remember-me service-ref="userService"/>

// after
<bean id="userService" class="com.app.UserService"/>
<bean id="uds" class="com.app.CustomUserDetailsService"/>
<remember-me service-ref="uds"/>
Defensive patterns

Strategy: type-guard

Validate before calling

Object bean = ctx.getBean(refName);
if (!(bean instanceof UserDetailsService) && !(bean instanceof AuthenticationUserDetailsService)) {
    throw new IllegalArgumentException(refName + " must be a UserDetailsService");
}

Type guard

function isUds(Object b) {
  return b instanceof org.springframework.security.core.userdetails.UserDetailsService
      || b instanceof org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
}

Try / catch

try { svc = factory.authenticationUserDetailsService(refName); }
catch (ApplicationContextException e) { log.error("Bean {} is not a UserDetailsService", refName, e); }

Prevention

When it happens

Trigger: An <http> remember-me service-ref or x509 service-ref points at a bean whose type is neither UserDetailsService nor AuthenticationUserDetailsService — e.g. referencing a plain DAO, a service class, or a bean typed Object/generic.

Common situations: Typo'd bean id that resolves to the wrong bean; refactoring moved UserDetails logic into a wrapper class no longer implementing UserDetailsService; using an XML ref to a @Component that doesn't implement the interface.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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