{"record":{"id":"96b4497b66bb37dc","repo":"quarkusio/quarkus","slug":"parameter-with-index-i-of-method-beanmethod-96b449","errorCode":null,"errorMessage":"Parameter with index <i> of method '<beanMethod>' found in expression '<expression>' in the @PreAuthorize annotation on method <method> of class <class> is not of type <expectedType>","messagePattern":"Parameter with index <i> of method '<beanMethod>' found in expression '<expression>' in the @PreAuthorize annotation on method <method> of class <class> is not of type <expectedType>","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions/spring-security/deployment/src/main/java/io/quarkus/spring/security/deployment/BeanMethodInvocationGenerator.java","lineNumber":192,"sourceCode":"                                        + \"' in the @PreAuthorize annotation on method \" + securedMethodInfo.name()\n                                        + \" of class \"\n                                        + securedMethodInfo.declaringClass() + \" is not of type String\");\n                            }\n\n                            argHandles.add(Const.of(argumentExpression.replace(\"'\", \"\")));\n                        } else if (trimmedArgumentExpression.matches(METHOD_PARAMETER_REGEX)) { // secured method's parameter case\n                            checkRequiresMethodArguments[0] = true;\n                            Matcher parameterMatcher = METHOD_PARAMETER_PATTERN.matcher(trimmedArgumentExpression);\n                            if (!parameterMatcher.find()) { // should never happen\n                                throw createGenericMalformedException(securedMethodInfo, expression);\n                            }\n\n                            // this is the index of the parameter we care about\n                            int parameterIndex = getParameterIndex(securedMethodInfo, parameterMatcher.group(1), expression);\n\n                            DotName expectedType = securedMethodInfo.parameterType(parameterIndex).name();\n                            if (!matchingBeanMethod.parameterType(i).name().equals(expectedType)) {\n                                throw new IllegalArgumentException(\"Parameter with index \" + i + \" of method '\" + beanMethodName\n                                        + \"' found in expression '\" + trimmedArgumentExpression\n                                        + \"' in the @PreAuthorize annotation on method \" + securedMethodInfo.name()\n                                        + \" of class \"\n                                        + securedMethodInfo.declaringClass() + \" is not of type \" + expectedType);\n                            }\n\n                            /*\n                             * the check method from AbstractBeanMethodSecurityCheck contains all parameters in an object array\n                             * so we need to use that to read the value at runtime\n                             */\n                            argHandles.add(bc.localVar(\"methodArg\" + parameterIndex,\n                                    bc.get(methodArgsParam.elem(parameterIndex))));\n                        } else if (trimmedArgumentExpression\n                                .matches(\"(authentication.)?principal.username\")) { // username use case\n                            LocalVar principal = bc.localVar(\"principal\", bc.invokeInterface(\n                                    MethodDesc.of(SecurityIdentity.class, \"getPrincipal\", Principal.class),\n                                    securityIdentityParam));\n","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/spring-security/deployment/src/main/java/io/quarkus/spring/security/deployment/BeanMethodInvocationGenerator.java#L174-L210","documentation":"When translating @PreAuthorize SpEL that passes a secured-method parameter into a bean method (e.g. @bean.check(#id)), the processor checks that the bean method's parameter type at index i equals the referenced secured-method parameter type. A mismatch means the generated bytecode invocation would not type-check, so the build fails.","triggerScenarios":"@PreAuthorize(\"@authz.canRead(#userId)\") where authz.canRead expects a type different from userId's type in the secured method (e.g. String vs Long), or an overloaded bean method matched the wrong variant.","commonSituations":"Refactoring one method without updating the SpEL; autoboxing mismatches (long vs Long); wrong overload picked among methods with the same name and parameter count.","solutions":["Align the bean method parameter type with the secured method parameter type (or vice versa)","Rename the bean method or adjust the SpEL to target the correct overload","Accept a wider type (e.g. Object) in the bean and convert inside","Reference the secured-method parameter by its exact name so getParameterIndex resolves correctly"],"exampleFix":"// before\n@PreAuthorize(\"@authz.canRead(#id)\") public void get(String id) // bean: canRead(long id)\n\n// after: bean method changed to\npublic boolean canRead(String id)","handlingStrategy":"type-guard","validationCode":"Class<?> expected = securedMethod.getParameterTypes()[refIndex];\nClass<?> actual = beanMethod.getParameterTypes()[i];\nif (!actual.equals(expected)) {\n    throw new IllegalStateException(\"SpEL arg type mismatch: \" + actual + \" vs \" + expected);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep @PreAuthorize-referenced bean params type-identical to secured method params","Watch autoboxing mismatches (long vs Long)","Update SpEL expressions whenever method signatures change"],"tags":["spring-security","preauthorize","spel","type-mismatch","build-time"],"backgroundTag":"spel-parameter-type-mismatch","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}