{"record":{"id":"ef03d8cdb252b414","repo":"quarkusio/quarkus","slug":"bean-named-beanname-found-in-expression-expr","errorCode":null,"errorMessage":"Bean named '<beanName>' found in expression '<expression>' in the @PreAuthorize annotation on method <method> of class <class> does not have a public field named '<fieldName>' of type String","messagePattern":"Bean named '<beanName>' found in expression '<expression>' in the @PreAuthorize annotation on method <method> of class <class> does not have a public field named '<fieldName>' of type String","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions/spring-security/deployment/src/main/java/io/quarkus/spring/security/deployment/HasRoleValueUtil.java","lineNumber":49,"sourceCode":"            SpringSecurityRecorder recorder) {\n        if (hasRoleValue.startsWith(\"'\") && hasRoleValue.endsWith(\"'\")) {\n            return recorder.staticHasRole(hasRoleValue.replace(\"'\", \"\"));\n        } else if (hasRoleValue.startsWith(\"@\")) {\n            Matcher beanFieldMatcher = BEAN_FIELD_PATTERN.matcher(hasRoleValue);\n            if (!beanFieldMatcher.find()) {\n                throw SpringSecurityProcessorUtil.createGenericMalformedException(methodInfo, hasRoleValue);\n            }\n\n            String beanName = beanFieldMatcher.group(1);\n            ClassInfo beanClassInfo = SpringSecurityProcessorUtil.getClassInfoFromBeanName(beanName, index,\n                    springBeansNameToDotName, springBeansNameToClassInfo, hasRoleValue, methodInfo);\n\n            String fieldName = beanFieldMatcher.group(2);\n            FieldInfo fieldInfo = beanClassInfo.field(fieldName);\n            //TODO: detect normal scoped beans and throw an exception, as it will read the field from the proxy\n            if ((fieldInfo == null) || !Modifier.isPublic(fieldInfo.flags())\n                    || !DotNames.STRING.equals(fieldInfo.type().name())) {\n                throw new IllegalArgumentException(\"Bean named '\" + beanName + \"' found in expression '\" + hasRoleValue\n                        + \"' in the @PreAuthorize annotation on method \" + methodInfo.name() + \" of class \"\n                        + methodInfo.declaringClass() + \" does not have a public field named '\" + fieldName\n                        + \"' of type String\");\n            }\n\n            beansReferencedInPreAuthorized.add(fieldInfo.declaringClass().name().toString());\n\n            return recorder.fromBeanField(fieldInfo.declaringClass().name().toString(), fieldName);\n        } else {\n            throw SpringSecurityProcessorUtil.createGenericMalformedException(methodInfo, hasRoleValue);\n        }\n    }\n\n}\n","sourceCodeStart":31,"sourceCodeEnd":64,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/spring-security/deployment/src/main/java/io/quarkus/spring/security/deployment/HasRoleValueUtil.java#L31-L64","documentation":"When a hasRole value references a bean field (@beanName.fieldName), Quarkus requires that field to exist, be public, and be of type String, because the generated check reads it directly at runtime. This IllegalArgumentException is thrown at build time when any of these conditions fails.","triggerScenarios":"getHasRoleValueProducer resolves @beanName.fieldName and the field is absent, non-public (private/protected/package-private), static, or of a type other than java.lang.String (e.g. boolean, List<String>).","commonSituations":"Referencing a private config field; referencing a constant of non-String type; renaming the field after writing the expression; using a getter-style path (@bean.someProperty) instead of an actual field.","solutions":["Make the referenced field public and of type String on the bean class","Change the expression to reference an existing public String field","If the value is not a String, convert it (e.g. add a public String field that mirrors the value) or restructure using a bean method check"],"exampleFix":"// before\n@Component\npublic class RolesConfig { private String adminRole = \"ROLE_ADMIN\"; }\n@PreAuthorize(\"hasRole(@rolesConfig.adminRole)\")\n\n// after\n@Component\npublic class RolesConfig { public String adminRole = \"ROLE_ADMIN\"; }\n@PreAuthorize(\"hasRole(@rolesConfig.adminRole)\")","handlingStrategy":"validation","validationCode":"Field f;\ntry { f = RolesConfig.class.getField(\"adminRole\"); }\ncatch (NoSuchFieldException e) { throw new IllegalStateException(\"missing field\"); }\nif (!java.lang.reflect.Modifier.isPublic(f.getModifiers()) || f.getType() != String.class)\n    throw new IllegalStateException(\"field must be public String\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Declare bean fields referenced in hasRole(@bean.field) as public String","Avoid referencing getters or non-String fields in these expressions","Keep the config bean and the expression in sync when renaming fields"],"tags":["spring-security","build-time","preauthorize","bean-field"],"backgroundTag":"preauthorize-bean-field-invalid","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"}