{"record":{"id":"189220398e9eb3d8","repo":"quarkusio/quarkus","slug":"parameter-with-index-i-of-method-beanmethod","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 String","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 String","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions/spring-security/deployment/src/main/java/io/quarkus/spring/security/deployment/BeanMethodInvocationGenerator.java","lineNumber":172,"sourceCode":"\n                mc.body(bc -> {\n                    LocalVar arcContainer = bc.localVar(\"arcContainer\", bc\n                            .invokeStatic(MethodDesc.of(Arc.class, \"container\", ArcContainer.class)));\n                    LocalVar instanceHandle = bc.localVar(\"instanceHandle\", bc.invokeInterface(\n                            MethodDesc.of(ArcContainer.class, \"instance\", InstanceHandle.class, String.class),\n                            arcContainer, Const.of(beanName)));\n                    LocalVar bean = bc.localVar(\"bean\", bc\n                            .invokeInterface(MethodDesc.of(InstanceHandle.class, \"get\", Object.class), instanceHandle));\n                    LocalVar castedBean = bc.localVar(\"castedBean\", bc.cast(bean, classDescOf(beanClassInfo)));\n\n                    List<Expr> argHandles = new ArrayList<>(finalBeanMethodArgumentExpressions.length);\n\n                    for (int i = 0; i < finalBeanMethodArgumentExpressions.length; i++) {\n                        String argumentExpression = finalBeanMethodArgumentExpressions[i];\n                        String trimmedArgumentExpression = argumentExpression.trim();\n                        if (argumentExpression.startsWith(\"'\") && argumentExpression.endsWith(\"'\")) { // hard coded string case\n                            if (!DotNames.STRING.equals(matchingBeanMethod.parameterType(i).name())) {\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 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();","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/spring-security/deployment/src/main/java/io/quarkus/spring/security/deployment/BeanMethodInvocationGenerator.java#L154-L190","documentation":"When generating a security check from a Spring Security @PreAuthorize SpEL expression, a quoted literal argument (e.g. @bean.method('x')) must match the corresponding bean method parameter type. The processor found the parameter at index i is not String, so the generated invocation would be type-unsafe, and the build fails.","triggerScenarios":"@PreAuthorize(\"@authz.check('literal')\") where the target bean method's parameter at that position is not String (e.g. int, long, enum).","commonSituations":"SpEL expressions copied from Spring apps where the target method signature changed; wrong bean method matched due to overloads; hardcoded literal quoting mismatched with a non-String parameter.","solutions":["Change the bean method parameter type to String, or remove the quotes so the literal matches a non-String parameter","Overload the bean method with a String-argument variant","Rewrite the SpEL to reference the secured method's parameters (#id) instead of literals","Convert the literal syntax to match the target parameter type"],"exampleFix":"// before: @PreAuthorize(\"@authz.hasRole('ADMIN')\") with bean method\npublic boolean hasRole(int level)\n\n// after\npublic boolean hasRole(String level) // or call hasRole(1) without quotes","handlingStrategy":"validation","validationCode":"// check literal argument vs bean method signature\nif (isQuotedLiteral(expr) && !beanMethod.getParameterTypes()[i].equals(String.class)) {\n    throw new IllegalStateException(\"Literal '\" + expr + \"' does not match non-String param \" + i);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Match quoted literals only with String parameters","Unquote literals for primitive/non-String parameters","Keep bean method signatures used in @PreAuthorize simple and reviewed"],"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-14T00:17:10.932Z"}