{"record":{"id":"c8fde873d9fa6452","repo":"spring-projects/spring-security","slug":"securitycontextresult-is-not-assignable-to-para","errorCode":null,"errorMessage":"<securityContextResult> is not assignable to <parameterType>","messagePattern":"<securityContextResult> is not assignable to <parameterType>","errorType":"exception","errorClass":"ClassCastException","httpStatus":null,"severity":"error","filePath":"web/src/main/java/org/springframework/security/web/reactive/result/method/annotation/CurrentSecurityContextArgumentResolver.java","lineNumber":158,"sourceCode":"\t\t}\n\t\treturn securityContext;\n\t}\n\n\tprivate @Nullable Object resolveSecurityContextFromAnnotation(CurrentSecurityContext annotation,\n\t\t\tMethodParameter parameter, Object securityContext) {\n\t\tObject securityContextResult = securityContext;\n\t\tString expressionToParse = annotation.expression();\n\t\tif (StringUtils.hasLength(expressionToParse)) {\n\t\t\tStandardEvaluationContext context = new StandardEvaluationContext();\n\t\t\tcontext.setRootObject(securityContext);\n\t\t\tcontext.setVariable(\"this\", securityContext);\n\t\t\tcontext.setBeanResolver(this.beanResolver);\n\t\t\tExpression expression = this.parser.parseExpression(expressionToParse);\n\t\t\tsecurityContextResult = expression.getValue(context);\n\t\t}\n\t\tif (isInvalidType(parameter, securityContextResult)) {\n\t\t\tif (annotation.errorOnInvalidType()) {\n\t\t\t\tthrow new ClassCastException(\n\t\t\t\t\t\tsecurityContextResult + \" is not assignable to \" + parameter.getParameterType());\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\t\treturn securityContextResult;\n\t}\n\n\t/**\n\t * check if the retrieved value match with the parameter type.\n\t * @param parameter the method parameter.\n\t * @param reactiveSecurityContext the security context.\n\t * @return true = is not invalid type.\n\t */\n\tprivate boolean isInvalidType(MethodParameter parameter, @Nullable Object reactiveSecurityContext) {\n\t\tif (reactiveSecurityContext == null) {\n\t\t\treturn false;\n\t\t}\n\t\tClass<?> typeToCheck = parameter.getParameterType();","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/web/src/main/java/org/springframework/security/web/reactive/result/method/annotation/CurrentSecurityContextArgumentResolver.java#L140-L176","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Align the declared parameter type with what the expression actually returns (inspect the SecurityContext contents at runtime or in a test).","Set @CurrentSecurityContext(errorOnInvalidType = false) to receive null on mismatch instead of throwing.","Fix the expression, e.g. change expression=\"authentication\" to expression=\"authentication.principal\" if you expect the principal object.","Ensure test setups populate the SecurityContext with the same concrete type production code produces."],"exampleFix":"// before\npublic Mono<String> who(@CurrentSecurityContext(expression = \"authentication\") MyUserDetails user) { ... }\n// after\npublic Mono<String> who(@CurrentSecurityContext(expression = \"authentication.principal\") MyUser user) { ... }","handlingStrategy":"type-guard","validationCode":"// Before invoking the handler, confirm the context type\nObject value = expression.getValue(context);\nif (!parameter.getParameterType().isInstance(value)) {\n    log.warn(\"@CurrentSecurityContext expression type mismatch: {} vs {}\",\n        value.getClass(), parameter.getParameterType());\n}","typeGuard":"// Java instanceof guard\nstatic boolean isAssignable(Object resolved, Class<?> targetType) {\n    return resolved != null && targetType.isInstance(resolved);\n}","tryCatchPattern":"try {\n    return resolveSecurityContextFromAnnotation(parameter, bindingContext);\n} catch (ClassCastException e) {\n    log.error(\"Security context type mismatch: {}\", e.getMessage());\n    return Mono.error(new ResponseStatusException(HttpStatus.UNAUTHORIZED));\n}","preventionTips":["Match SpEL expression output type to the declared parameter type","Use errorOnInvalidType=false when null is an acceptable outcome","Mirror production SecurityContext types in tests","Avoid expressions returning nested objects of uncertain type"],"tags":["spring-security","reactive","webflux","classcastexception","type-mismatch"],"backgroundTag":"type-mismatch","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}