spring-projects/spring-security · error · ServletException
<ex.getMessage()>
Error message
<ex.getMessage()>
What it means
When the wrapper's getAuthentication() delegates to the configured AuthenticationManager and authentication fails (AuthenticationException), the security context is cleared and the exception is rethrown as a ServletException whose message is the original exception message, with the original as cause. This exposes programmatic-authentication failures to the servlet API caller while ensuring no stale authentication remains.
Solutions
- Inspect the ServletException cause for the concrete AuthenticationException subclass and message
- Correct the credentials or account state the caller supplied
- Catch ServletException and map to an appropriate login-failure response instead of a 500
- Verify AuthenticationManager/provider configuration if even valid credentials fail
Example fix
// before
request.authenticate(response);
// after
try {
request.authenticate(response);
} catch (ServletException e) {
logger.warn("Authentication failed: " + e.getMessage());
// render login-failure view
} Defensive patterns
Strategy: try-catch
Validate before calling
// validate credentials are present before attempting authentication
if (username == null || username.isBlank() || password == null || password.isEmpty()) {
throw new IllegalArgumentException("Username and password required");
} Try / catch
try {
request.login(user, pass);
return true;
} catch (ServletException ex) {
Throwable cause = ex.getCause();
if (cause instanceof AuthenticationException authEx) {
// e.g. BadCredentialsException, DisabledException
return handleAuthFailure(authEx);
}
throw ex;
} Prevention
- Always inspect getCause() for the concrete AuthenticationException type
- Give users actionable messages (account locked vs bad credentials) based on the cause
- Pre-clear the SecurityContext before programmatic re-authentication
- Test login failure paths (locked, disabled, expired accounts) in integration tests
When it happens
Trigger: Calling request.authenticate(request)/the wrapper's authentication path when the AuthenticationManager rejects the credentials or token — e.g. BadCredentialsException, DisabledException, LockedException raised inside authenticate().
Common situations: Wrong username/password supplied to programmatic login; account disabled/locked/expired; an AuthenticationProvider throwing due to misconfiguration; token no longer valid at authenticate() time.
Related errors
- Cannot perform login for
- AccountStatusUserDetailsChecker.disabled
- AccountStatusUserDetailsChecker.expired
- An Authentication object was not found in the…
- Authenticated principal required to operate with ACLs
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/af1b277fe362e219.
Report an issue: GitHub.
Appendix: source
Thrown at web/src/main/java/org/springframework/security/web/servletapi/HttpServlet3RequestFactory.java:266
SecurityContext context = HttpServlet3RequestFactory.this.securityContextHolderStrategy
.createEmptyContext();
context.setAuthentication(authentication);
HttpServlet3RequestFactory.this.securityContextHolderStrategy.setContext(context);
HttpServlet3RequestFactory.this.securityContextRepository.saveContext(context, this, this.response);
}
private Authentication getAuthentication(AuthenticationManager authManager, String username, String password)
throws ServletException {
try {
UsernamePasswordAuthenticationToken authentication = UsernamePasswordAuthenticationToken
.unauthenticated(username, password);
Object details = HttpServlet3RequestFactory.this.authenticationDetailsSource.buildDetails(this);
authentication.setDetails(details);
return authManager.authenticate(authentication);
}
catch (AuthenticationException ex) {
HttpServlet3RequestFactory.this.securityContextHolderStrategy.clearContext();
throw new ServletException(ex.getMessage(), ex);
}
}
@Override
public void logout() throws ServletException {
List<LogoutHandler> handlers = HttpServlet3RequestFactory.this.logoutHandlers;
if (CollectionUtils.isEmpty(handlers)) {
HttpServlet3RequestFactory.this.logger
.debug("logoutHandlers is null, so allowing original HttpServletRequest to handle logout");
super.logout();
return;
}
Authentication authentication = HttpServlet3RequestFactory.this.securityContextHolderStrategy.getContext()
.getAuthentication();
for (LogoutHandler handler : handlers) {
handler.logout(this, this.response, authentication);
}
}View on GitHub (pinned to 96852e8860)