{"record":{"id":"4c89479c75a9e9ed","repo":"spring-projects/spring-security","slug":"securitycontextresult-is-not-assignable-to","errorCode":null,"errorMessage":"securityContextResult + \" is not assignable to \" + parameter.getParameterType()","messagePattern":"securityContextResult \\+ \" is not assignable to \" \\+ parameter\\.getParameterType\\(\\)","errorType":"exception","errorClass":"ClassCastException","httpStatus":null,"severity":"error","filePath":"web/src/main/java/org/springframework/security/web/method/annotation/CurrentSecurityContextArgumentResolver.java","lineNumber":170,"sourceCode":"\t\tthis.scanner = SecurityAnnotationScanners.requireUnique(CurrentSecurityContext.class, templateDefaults);\n\t}\n\n\tprivate @Nullable Object resolveSecurityContextFromAnnotation(MethodParameter parameter,\n\t\t\tCurrentSecurityContext annotation, SecurityContext 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 (securityContextResult != null\n\t\t\t\t&& !parameter.getParameterType().isAssignableFrom(securityContextResult.getClass())) {\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 * Obtain the specified {@link Annotation} on the specified {@link MethodParameter}.\n\t * @param parameter the {@link MethodParameter} to search for an {@link Annotation}\n\t * @return the {@link Annotation} that was found or null.\n\t */\n\tprivate @Nullable CurrentSecurityContext findMethodAnnotation(MethodParameter parameter) {\n\t\tif (this.useAnnotationTemplate) {\n\t\t\treturn this.scanner.scan(parameter.getParameter());\n\t\t}\n\t\tCurrentSecurityContext annotation = parameter.getParameterAnnotation(this.annotationType);\n\t\tif (annotation != null) {","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/web/src/main/java/org/springframework/security/web/method/annotation/CurrentSecurityContextArgumentResolver.java#L152-L188","documentation":"Thrown by CurrentSecurityContextArgumentResolver when a @CurrentSecurityContext annotated parameter cannot receive the resolved security context object because its declared Java type is not assignable from the actual result's class. Spring Security throws this (as ClassCastException) only when errorOnInvalidType() is true on the annotation; otherwise it silently returns null.","triggerScenarios":"A controller/handler method declares @CurrentSecurityContext SomeType param, the SpEL expression (default 'authentication' or a custom expression) evaluates to an object whose class is not assignable to SomeType (e.g. expression='authentication' but parameter type is CustomUserDetails, or expression returns Authentication but parameter is String).","commonSituations":"Declaring a parameter as a concrete UserDetails implementation while the principal is a different type; using a custom SpEL expression whose result type differs from the parameter type; copy-pasting resolvers across apps with different Authentication implementations; Spring Security 5.x where errorOnInvalidType defaults changed semantics for expression-based resolution.","solutions":["Change the parameter's declared type to a supertype actually produced by the expression (e.g. Authentication, SecurityContext, Object) and downcast safely in the body","Align the annotation's expression with the parameter type, e.g. @CurrentSecurityContext(expression = \"authentication.principal\") with parameter type matching the actual principal class","If a null is acceptable on mismatch, set @CurrentSecurityContext(errorOnInvalidType = false) so the resolver returns null instead of throwing","Check what the expression actually returns (SecurityContextHolder.getContext().getAuthentication().getClass()) and fix the mismatch"],"exampleFix":"// before\npublic Me me(@CurrentSecurityContext(expression = \"authentication.principal\") CustomUser user) { ... }\n// after\npublic Me me(@CurrentSecurityContext(expression = \"authentication.principal\") Object principal) {\n    CustomUser user = (principal instanceof CustomUser u) ? u : null;\n    ...\n}","handlingStrategy":"validation","validationCode":"Object result = SecurityContextHolder.getContext().getAuthentication().getPrincipal();\nif (!parameterType.isAssignableFrom(result.getClass())) {\n    // fix annotation expression or parameter type before deployment\n}","typeGuard":"static <T> T safePrincipal(Class<T> type) {\n    Object p = SecurityContextHolder.getContext().getAuthentication().getPrincipal();\n    return type.isInstance(p) ? type.cast(p) : null;\n}","tryCatchPattern":"try {\n    return resolver.resolveArgument(param, null, request, null);\n} catch (ClassCastException e) {\n    log.warn(\"@CurrentSecurityContext type mismatch for {}: {}\", param, e.getMessage());\n    return null; // or map to 400\n}","preventionTips":["Declare @CurrentSecurityContext parameters as Authentication, SecurityContext, or Object unless the expression guarantees the concrete type","Match the SpEL expression to the parameter type (authentication.principal for UserDetails types)","Use errorOnInvalidType = false when a null is an acceptable outcome","Add an integration test resolving the annotation for each Authentication implementation you support"],"tags":["spring-security","type-mismatch","spel","argument-resolver"],"backgroundTag":"type-mismatch","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}