spring-projects/spring-security · error · DisabledException
AbstractUserDetailsAuthenticationProvider.disabled
AbstractUserDetailsAuthenticationProvider.disabled
Error message
User is disabled
What it means
defaultPreAuthenticationChecks in AbstractUserDetailsReactiveAuthenticationManager throws DisabledException with 'User is disabled' (message code AbstractUserDetailsAuthenticationProvider.disabled) when UserDetails.isEnabled() returns false. The account exists but is flagged disabled, so authentication fails before credential checking.
Source
Thrown at core/src/main/java/org/springframework/security/authentication/AbstractUserDetailsReactiveAuthenticationManager.java:82
private ReactiveUserDetailsPasswordService userDetailsPasswordService = ReactiveUserDetailsPasswordService.NOOP;
private Scheduler scheduler = Schedulers.boundedElastic();
private UserDetailsChecker preAuthenticationChecks = this::defaultPreAuthenticationChecks;
private UserDetailsChecker postAuthenticationChecks = this::defaultPostAuthenticationChecks;
private @Nullable ReactiveCompromisedPasswordChecker compromisedPasswordChecker;
private void defaultPreAuthenticationChecks(UserDetails user) {
if (!user.isAccountNonLocked()) {
this.logger.debug("User account is locked");
throw new LockedException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.locked",
"User account is locked"));
}
if (!user.isEnabled()) {
this.logger.debug("User account is disabled");
throw new DisabledException(
this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.disabled", "User is disabled"));
}
if (!user.isAccountNonExpired()) {
this.logger.debug("User account is expired");
throw new AccountExpiredException(this.messages
.getMessage("AbstractUserDetailsAuthenticationProvider.expired", "User account has expired"));
}
}
private void defaultPostAuthenticationChecks(UserDetails user) {
if (!user.isCredentialsNonExpired()) {
this.logger.debug("User account credentials have expired");
throw new CredentialsExpiredException(this.messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.credentialsExpired", "User credentials have expired"));
}
}
@OverrideView on GitHub (pinned to 96852e8860)
Solutions
- Set the enabled flag true in your user store, or override isEnabled() to return true when appropriate
- Complete whatever activation flow (email verification) gates the enabled flag
- Catch DisabledException in the reactive chain and show an account-disabled message
- Verify your UserDetails implementation implements isEnabled() rather than relying on interface defaults
Example fix
// before
class AppUser implements UserDetails { /* isEnabled() not overridden -> false */ }
// after
class AppUser implements UserDetails {
@Override public boolean isEnabled() { return this.active; }
} Defensive patterns
Strategy: try-catch
Validate before calling
if (!userDetails.isEnabled()) throw new DisabledException("Account disabled: " + username); Type guard
boolean loginAllowed(UserDetails u) { return u.isEnabled(); } Try / catch
authManager.authenticate(token)
.onErrorResume(DisabledException.class, e -> Mono.error(new AuthFailure("ACCOUNT_DISABLED"))); Prevention
- Override isEnabled() in custom UserDetails implementations
- Gate enabled flag behind a completed activation flow
- Seed test users with enabled=true
- Keep enabled column default consistent with business rules
When it happens
Trigger: authenticate() receiving a UserDetails with isEnabled() == false — e.g. users.enabled=0 in the database, or a custom UserDetails class that does not override isEnabled() (interface default returns false).
Common situations: Newly registered users pending email verification; admin-deactivated accounts; custom UserDetails implementations forgetting to implement isEnabled(); schema migrations zeroing the enabled column.
Related errors
- AbstractUserDetailsAuthenticationProvider.locked
- AbstractUserDetailsAuthenticationProvider.expired
- AbstractUserDetailsAuthenticationProvider.credentialsExpired
- AccountStatusUserDetailsChecker.locked
- AccountStatusUserDetailsChecker.disabled
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/385c28ceb4a1d986.
Report an issue: GitHub.