spring-projects/spring-security · error · ClassCastException

<securityContextResult> is not assignable to <parameterType>

Error message

<securityContextResult> is not assignable to <parameterType>

What it means

The @CurrentSecurityContext argument resolver in Spring Security's reactive web support evaluates the (possibly SpEL expression) value of the security context. If the resolved object cannot be assigned to the controller method parameter type and annotation.errorOnInvalidType() is true, a ClassCastException is thrown. It exists to surface silent type mismatches between the SecurityContext contents and the declared parameter.

Source

Thrown at web/src/main/java/org/springframework/security/web/reactive/result/method/annotation/CurrentSecurityContextArgumentResolver.java:158

		}
		return securityContext;
	}

	private @Nullable Object resolveSecurityContextFromAnnotation(CurrentSecurityContext annotation,
			MethodParameter parameter, Object securityContext) {
		Object securityContextResult = securityContext;
		String expressionToParse = annotation.expression();
		if (StringUtils.hasLength(expressionToParse)) {
			StandardEvaluationContext context = new StandardEvaluationContext();
			context.setRootObject(securityContext);
			context.setVariable("this", securityContext);
			context.setBeanResolver(this.beanResolver);
			Expression expression = this.parser.parseExpression(expressionToParse);
			securityContextResult = expression.getValue(context);
		}
		if (isInvalidType(parameter, securityContextResult)) {
			if (annotation.errorOnInvalidType()) {
				throw new ClassCastException(
						securityContextResult + " is not assignable to " + parameter.getParameterType());
			}
			return null;
		}
		return securityContextResult;
	}

	/**
	 * check if the retrieved value match with the parameter type.
	 * @param parameter the method parameter.
	 * @param reactiveSecurityContext the security context.
	 * @return true = is not invalid type.
	 */
	private boolean isInvalidType(MethodParameter parameter, @Nullable Object reactiveSecurityContext) {
		if (reactiveSecurityContext == null) {
			return false;
		}
		Class<?> typeToCheck = parameter.getParameterType();

View on GitHub (pinned to 96852e8860)

Solutions

  1. Align the declared parameter type with what the expression actually returns (inspect the SecurityContext contents at runtime or in a test).
  2. Set @CurrentSecurityContext(errorOnInvalidType = false) to receive null on mismatch instead of throwing.
  3. Fix the expression, e.g. change expression="authentication" to expression="authentication.principal" if you expect the principal object.
  4. Ensure test setups populate the SecurityContext with the same concrete type production code produces.

Example fix

// before
public Mono<String> who(@CurrentSecurityContext(expression = "authentication") MyUserDetails user) { ... }
// after
public Mono<String> who(@CurrentSecurityContext(expression = "authentication.principal") MyUser user) { ... }
Defensive patterns

Strategy: type-guard

Validate before calling

// Before invoking the handler, confirm the context type
Object value = expression.getValue(context);
if (!parameter.getParameterType().isInstance(value)) {
    log.warn("@CurrentSecurityContext expression type mismatch: {} vs {}",
        value.getClass(), parameter.getParameterType());
}

Type guard

// Java instanceof guard
static boolean isAssignable(Object resolved, Class<?> targetType) {
    return resolved != null && targetType.isInstance(resolved);
}

Try / catch

try {
    return resolveSecurityContextFromAnnotation(parameter, bindingContext);
} catch (ClassCastException e) {
    log.error("Security context type mismatch: {}", e.getMessage());
    return Mono.error(new ResponseStatusException(HttpStatus.UNAUTHORIZED));
}

Prevention

When it happens

Trigger: A handler declares @CurrentSecurityContext(expression = "authentication") Authentication auth or a concrete type (e.g. MyUserDetails), but the expression resolves to a different type while errorOnInvalidType is true (default).

Common situations: Expression returns a nested object of the wrong type (e.g. authentication.principal is a String); switching from servlet to reactive stack with different Authentication implementations; tests populating the SecurityContext with a mock of a different concrete type.

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