quarkusio/quarkus · error · IllegalStateException

Currently expressions containing both logical 'and' / 'or' a

Error message

Currently expressions containing both logical 'and' / 'or' are not supported. Offending expression is <value>' in the @PreAuthorize annotation on method '<method>' of class '<class>

What it means

Quarkus's Spring Security expression subset cannot evaluate an expression containing both logical 'and' and 'or' operators. addSpringPreAuthorizeSecurityCheck detects both in the @PreAuthorize value and throws this IllegalStateException at build time. (Note the message has an unbalanced quote — cosmetic.)

Source

Thrown at extensions/spring-security/deployment/src/main/java/io/quarkus/spring/security/deployment/SpringSecurityProcessor.java:427

            MethodInfo methodInfo = entry.getKey();
            String value = instance.value().asString().trim();

            /*
             * TODO: this serves fine for most purposes but a full-blown solution will need a proper parser
             */

            boolean containsAnd = false;
            boolean containsOr = false;
            String lowercaseValue = value.toLowerCase();
            if (lowercaseValue.contains(" or ")) {
                containsOr = true;
            }
            if (lowercaseValue.contains(" and ")) {
                containsAnd = true;
            }

            if (containsAnd && containsOr) {
                throw new IllegalStateException(
                        "Currently expressions containing both logical 'and' / 'or' are not supported. Offending expression is "
                                + value + "' in the @PreAuthorize annotation on method '" + methodInfo.name()
                                + "' of class '" + methodInfo.declaringClass());
            }

            String[] parts = { value };
            if (containsAnd) {
                parts = value.split("(?i) and ");
            } else if (containsOr) {
                parts = value.split("(?i) or ");
            }

            List<SecurityCheck> securityChecks = new ArrayList<>(parts.length);

            for (String part : parts) {
                part = part.trim();
                if (part.equals("permitAll()")) {
                    securityChecks.add(securityCheckRecorder.permitAll());

View on GitHub (pinned to e1c734241f)

Solutions

  1. Split the logic: keep the simpler conditions in @PreAuthorize and move the compound decision into a public boolean bean method invoked as @PreAuthorize("@authz.canAccess(#x)")
  2. Use only 'and' or only 'or' in the expression if it can be restructured (single operator forms are supported)
  3. Drop parentheses-dependent logic entirely and evaluate it in application code or a custom SecurityCheck

Example fix

// before
@PreAuthorize("hasRole('admin') and #user == principalUsername or isAnonymous()")

// after
@PreAuthorize("@authz.canAccess(#user)") // public boolean canAccess(String user) { ... }
Defensive patterns

Strategy: validation

Validate before calling

String v = "hasRole('admin') and hasRole('user')";
String lc = v.toLowerCase();
if (lc.contains(" and ") && lc.contains(" or "))
    throw new IllegalStateException("Both 'and' and 'or' unsupported: " + v);

Prevention

When it happens

Trigger: An expression like "hasRole('admin') and hasRole('user') or isAuthenticated()" — where the lowercased value contains both " and " and " or " — triggers the check.

Common situations: Porting complex Spring SpEL security rules unchanged; combining role checks with other conditions in one annotation; writing compound authorization rules.

Related errors


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