spring-projects/spring-security · warning

AuthenticationException must be of type %s but was %s

Error message

AuthenticationException must be of type %s but was %s

What it means

OAuth2ErrorAuthenticationFailureHandler.onAuthenticationFailure() can only render OAuth2 errors; if the thrown AuthenticationException is not an OAuth2AuthenticationException it cannot convert it to an error response, so it only logs a warning naming the actual exception type and returns without writing a response.

Source

Thrown at oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/authentication/OAuth2ErrorAuthenticationFailureHandler.java:65

public final class OAuth2ErrorAuthenticationFailureHandler implements AuthenticationFailureHandler {

	private final Log logger = LogFactory.getLog(getClass());

	private HttpMessageConverter<OAuth2Error> errorResponseConverter = new OAuth2ErrorHttpMessageConverter();

	@Override
	public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
			AuthenticationException authenticationException) throws IOException, ServletException {
		ServletServerHttpResponse httpResponse = new ServletServerHttpResponse(response);
		httpResponse.setStatusCode(HttpStatus.BAD_REQUEST);

		if (authenticationException instanceof OAuth2AuthenticationException oauth2AuthenticationException) {
			OAuth2Error error = oauth2AuthenticationException.getError();
			this.errorResponseConverter.write(error, null, httpResponse);
		}
		else {
			if (this.logger.isWarnEnabled()) {
				this.logger.warn(AuthenticationException.class.getSimpleName() + " must be of type "
						+ OAuth2AuthenticationException.class.getName() + " but was "
						+ authenticationException.getClass().getName());
			}
		}
	}

	/**
	 * Sets the {@link HttpMessageConverter} used for converting an {@link OAuth2Error} to
	 * an HTTP response.
	 * @param errorResponseConverter the {@link HttpMessageConverter} used for converting
	 * an {@link OAuth2Error} to an HTTP response
	 */
	public void setErrorResponseConverter(HttpMessageConverter<OAuth2Error> errorResponseConverter) {
		Assert.notNull(errorResponseConverter, "errorResponseConverter cannot be null");
		this.errorResponseConverter = errorResponseConverter;
	}

}

View on GitHub (pinned to 96852e8860)

Solutions

  1. Find which provider/filter throws the non-OAuth2 exception and make it throw OAuth2AuthenticationException with a proper OAuth2Error
  2. Register this handler only on filters that exclusively produce OAuth2AuthenticationException (e.g. OAuth2 authorization endpoint, token endpoint)
  3. Add a fallback AuthenticationFailureHandler that handles generic AuthenticationExceptions

Example fix

// before
throw new BadCredentialsException("invalid token");
// after
throw new OAuth2AuthenticationException(new OAuth2Error("invalid_token", "invalid token", null));
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(ex instanceof OAuth2AuthenticationException)) {
    logger.warn("Non-OAuth2 AuthenticationException routed to OAuth2ErrorAuthenticationFailureHandler: " + ex.getClass().getName());
}

Type guard

if (authenticationException instanceof OAuth2AuthenticationException oauth2Ex) {
    // safe: handler can render oauth2Ex.getError()
}

Try / catch

try {
    filterChain.doFilter(request, response);
} catch (AuthenticationException ex) {
    OAuth2Error error = (ex instanceof OAuth2AuthenticationException o) ? o.getError()
        : new OAuth2Error("server_error", ex.getMessage(), null);
    // write error via converter
}

Prevention

When it happens

Trigger: Registering an OAuth2ErrorAuthenticationFailureHandler on an authentication filter/endpoint where a non-OAuth2 AuthenticationException (e.g. BadCredentialsException, UsernameNotFoundException, DisabledException) can be thrown.

Common situations: Wiring the OAuth2 failure handler into the standard form-login or bearer-token failure path by mistake; custom providers throwing plain BadCredentialsException inside an OAuth2 flow.

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/a06fe8cfe3437685. Report an issue: GitHub.