{"record":{"id":"f8e3888d59b4c328","repo":"quarkusio/quarkus","slug":"class-s-is-annotated-with-multiple-security-annot","errorCode":null,"errorMessage":"Class %s is annotated with multiple security annotations %s and %s","messagePattern":"Class (.+?) is annotated with multiple security annotations (.+?) and (.+?)","errorType":"exception","errorClass":"java.lang.IllegalStateException","httpStatus":null,"severity":"error","filePath":"extensions/security/deployment/src/main/java/io/quarkus/security/deployment/PermissionSecurityChecks.java","lineNumber":497,"sourceCode":"                                }\n\n                                if (hasAdditionalSecurityAnnotations.test(methodInfo)) {\n                                    continue;\n                                }\n\n                                // ignore method annotated with other security annotation\n                                boolean noMethodLevelSecurityAnnotation = !alreadyCheckedMethods.containsKey(methodInfo);\n                                // ignore method annotated with method-level @PermissionsAllowed\n                                boolean noMethodLevelPermissionsAllowed = !targetToPermissionKeys.containsKey(methodInfo);\n                                if (noMethodLevelSecurityAnnotation && noMethodLevelPermissionsAllowed) {\n\n                                    gatherPermissionKeys(instance, methodInfo, cache, classMethodToPermissionKeys);\n                                }\n                            }\n                        } else {\n\n                            // we do not allow combining @PermissionsAllowed with other security annotations as @Authenticated\n                            throw new IllegalStateException(\n                                    String.format(\"Class %s is annotated with multiple security annotations %s and %s\", clazz,\n                                            instance.name(), existingClassInstance.name()));\n                        }\n                    }\n                }\n            }\n            targetToPermissionKeys.putAll(classMethodToPermissionKeys);\n            for (var instance : additionalClassInstances) {\n                gatherPermissionKeys(instance, instance.target(), cache, targetToPermissionKeys);\n            }\n\n            // for validation purposes, so that we detect correctly combinations with other security annotations\n            var targetInstances = new ArrayList<>(permissionInstances);\n            targetInstances.addAll(additionalClassInstances);\n            targetToPermissionKeys.keySet().forEach(at -> {\n                if (at.kind() == AnnotationTarget.Kind.CLASS) {\n                    var classInfo = at.asClass();\n                    alreadyCheckedClasses.put(classInfo, getAnnotationInstance(classInfo, targetInstances));","sourceCodeStart":479,"sourceCodeEnd":515,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/security/deployment/src/main/java/io/quarkus/security/deployment/PermissionSecurityChecks.java#L479-L515","documentation":"A class was annotated with @PermissionsAllowed and also with another class-level security annotation (e.g. @Authenticated, @RolesAllowed). Combining @PermissionsAllowed with other security annotations at class level is not allowed because it makes authorization ambiguous; Quarkus reports the two conflicting annotation names and fails the build.","triggerScenarios":"Placing @PermissionsAllowed on a class that also carries @Authenticated/@RolesAllowed/@DenyAll etc.; detected in gatherPermissionsAllowedAnnotations when an existingClassInstance for the same class has a different annotation name.","commonSituations":"Adding @PermissionsAllowed to an already-secured class when tightening authorization; applying annotations from different security generations (legacy RBAC vs the permission-checker API) to the same bean.","solutions":["Remove the other class-level security annotation, keeping only @PermissionsAllowed","Convert the other annotation's policy into a @PermissionChecker + permission name used by @PermissionsAllowed","If both policies are genuinely needed, apply them at different levels consistently within one annotation system"],"exampleFix":"// before\n@Authenticated\n@PermissionsAllowed(value=\"book:read\", action=BookPerm.class)\npublic class BookResource {...}\n\n// after\n@PermissionsAllowed(value=\"book:read\", action=BookPerm.class)\npublic class BookResource {...}","handlingStrategy":"validation","validationCode":"for (Annotation a : BookResource.class.getAnnotations()) {\n    if (!(a instanceof PermissionsAllowed) && SECURITY_ANNOTATIONS.contains(a.annotationType()))\n        throw new IllegalStateException(\"@PermissionsAllowed must not be combined with \" + a.annotationType());\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pick one authorization model (RBAC or permission checkers) per class","Review class-level annotations when introducing @PermissionsAllowed","Keep security annotations in the class Javadoc for visibility"],"tags":["quarkus","security","build-time","annotations-conflict"],"backgroundTag":"conflicting-security-annotations","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"}