{"record":{"id":"a89a6404b0389796","repo":"quarkusio/quarkus","slug":"expression-part-in-the-preauthorize-annotati","errorCode":null,"errorMessage":"Expression: '<part>' in the @PreAuthorize annotation on method '<method>' of class '<class>' is malformed","messagePattern":"Expression: '<part>' in the @PreAuthorize annotation on method '<method>' of class '<class>' is malformed","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions/spring-security/deployment/src/main/java/io/quarkus/spring/security/deployment/SpringSecurityProcessor.java","lineNumber":338,"sourceCode":"            String value = instance.value().asString().trim();\n\n            String[] parts = { value };\n            if (value.toLowerCase().contains(\" and \")) {\n                parts = value.split(\"(?i) and \");\n            } else if (value.toLowerCase().contains(\" or \")) {\n                parts = value.split(\"(?i) or \");\n            }\n\n            /*\n             * this is essentially the same loop as in addSpringPreAuthorizeSecurityCheck but only deals with cases\n             * where beans need to be generated\n             */\n            for (String part : parts) {\n                part = part.trim();\n                if (part.matches(PARAMETER_EQ_PRINCIPAL_USERNAME_REGEX)) {\n                    Matcher matcher = PARAMETER_EQ_PRINCIPAL_USERNAME_PATTERN.matcher(part);\n                    if (!matcher.find()) { // should never happen\n                        throw SpringSecurityProcessorUtil.createGenericMalformedException(methodInfo, part);\n                    }\n\n                    ParameterNameAndIndex parameterNameAndIndex = getParameterNameAndIndexForPrincipalUserNameReference(\n                            methodInfo,\n                            matcher, part);\n\n                    String propertyName = matcher.group(PARAMETER_EQ_PRINCIPAL_USERNAME_PROPERTY_ACCESSOR_MATCHER_GROUP);\n                    if (propertyName != null) {\n                        /*\n                         * In this we need to call a getter method on the parameter. In order to do that we need to generate\n                         * an accessor for that method (which is ensured to return type String since that is the type of the\n                         * username).\n                         */\n                        StringPropertyAccessorData stringPropertyAccessorData = StringPropertyAccessorData.from(\n                                methodInfo, parameterNameAndIndex.getIndex(),\n                                propertyName, index.getIndex(),\n                                part);\n","sourceCodeStart":320,"sourceCodeEnd":356,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/spring-security/deployment/src/main/java/io/quarkus/spring/security/deployment/SpringSecurityProcessor.java#L320-L356","documentation":"The processor supports @PreAuthorize expressions of the form principalUsername == #param (parameter equal-to / not-equal-to principal name). When a part of the expression matches the parameter-eq-principal-username shape but the regex capture fails, this generic malformed-expression IllegalArgumentException is thrown at build time (comment says 'should never happen').","triggerScenarios":"An expression part matches PARAMETER_EQ_PRINCIPAL_USERNAME_REGEX after trimming, but the second, stricter matcher (PARAMETER_EQ_PRINCIPAL_USERNAME_PATTERN) fails to find groups in generateNecessarySupportClasses.","commonSituations":"Very rare — essentially an internal consistency failure; could surface with unusual whitespace or exotic characters in expressions that satisfy one regex but not the other.","solutions":["Rewrite the expression in the canonical supported form: principalUsername == #paramName or principalUsername != #paramName","Remove odd whitespace/characters from the expression","If the check persists on a simple expression, restructure as a bean-method check: @PreAuthorize(\"@authz.matches(#name)\")"],"exampleFix":"// before\n@PreAuthorize(\"#username==principal.username\")\n\n// after\n@PreAuthorize(\"principalUsername == #username\")","handlingStrategy":"validation","validationCode":"String expr = \"principalUsername == #username\";\njava.util.regex.Pattern p = java.util.regex.Pattern.compile(\"(principalUsername|principal.username)\\\\s*(!?=)\\\\s*#\\\\w+\");\nif (!p.matcher(expr).find()) throw new IllegalArgumentException(\"Unsupported form: \" + expr);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Write parameter-vs-principal checks only in the documented form principalUsername == #param","Avoid exotic whitespace or alternate spellings in expressions","Prefer bean-method checks for anything beyond the supported patterns"],"tags":["spring-security","build-time","preauthorize","malformed-expression"],"backgroundTag":"malformed-preauthorize-expression","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"}