quarkusio/quarkus · error · IllegalArgumentException

Bean named '<beanName>' found in expression '<expression>' i

Error message

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

What it means

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.

Source

Thrown at extensions/spring-security/deployment/src/main/java/io/quarkus/spring/security/deployment/HasRoleValueUtil.java:49

            SpringSecurityRecorder recorder) {
        if (hasRoleValue.startsWith("'") && hasRoleValue.endsWith("'")) {
            return recorder.staticHasRole(hasRoleValue.replace("'", ""));
        } else if (hasRoleValue.startsWith("@")) {
            Matcher beanFieldMatcher = BEAN_FIELD_PATTERN.matcher(hasRoleValue);
            if (!beanFieldMatcher.find()) {
                throw SpringSecurityProcessorUtil.createGenericMalformedException(methodInfo, hasRoleValue);
            }

            String beanName = beanFieldMatcher.group(1);
            ClassInfo beanClassInfo = SpringSecurityProcessorUtil.getClassInfoFromBeanName(beanName, index,
                    springBeansNameToDotName, springBeansNameToClassInfo, hasRoleValue, methodInfo);

            String fieldName = beanFieldMatcher.group(2);
            FieldInfo fieldInfo = beanClassInfo.field(fieldName);
            //TODO: detect normal scoped beans and throw an exception, as it will read the field from the proxy
            if ((fieldInfo == null) || !Modifier.isPublic(fieldInfo.flags())
                    || !DotNames.STRING.equals(fieldInfo.type().name())) {
                throw new IllegalArgumentException("Bean named '" + beanName + "' found in expression '" + hasRoleValue
                        + "' in the @PreAuthorize annotation on method " + methodInfo.name() + " of class "
                        + methodInfo.declaringClass() + " does not have a public field named '" + fieldName
                        + "' of type String");
            }

            beansReferencedInPreAuthorized.add(fieldInfo.declaringClass().name().toString());

            return recorder.fromBeanField(fieldInfo.declaringClass().name().toString(), fieldName);
        } else {
            throw SpringSecurityProcessorUtil.createGenericMalformedException(methodInfo, hasRoleValue);
        }
    }

}

View on GitHub (pinned to e1c734241f)

Solutions

  1. Make the referenced field public and of type String on the bean class
  2. Change the expression to reference an existing public String field
  3. 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

Example fix

// before
@Component
public class RolesConfig { private String adminRole = "ROLE_ADMIN"; }
@PreAuthorize("hasRole(@rolesConfig.adminRole)")

// after
@Component
public class RolesConfig { public String adminRole = "ROLE_ADMIN"; }
@PreAuthorize("hasRole(@rolesConfig.adminRole)")
Defensive patterns

Strategy: validation

Validate before calling

Field f;
try { f = RolesConfig.class.getField("adminRole"); }
catch (NoSuchFieldException e) { throw new IllegalStateException("missing field"); }
if (!java.lang.reflect.Modifier.isPublic(f.getModifiers()) || f.getType() != String.class)
    throw new IllegalStateException("field must be public String");

Prevention

When it happens

Trigger: 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>).

Common situations: 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.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/ef03d8cdb252b414. Report an issue: GitHub.