{"record":{"id":"f3f24bb09b697229","repo":"quarkusio/quarkus","slug":"method-s-of-class-s-is-annotated-with-multiple-s","errorCode":null,"errorMessage":"Method %s of class %s is annotated with multiple security annotations","messagePattern":"Method (.+?) of class (.+?) is annotated with multiple security annotations","errorType":"exception","errorClass":"java.lang.IllegalStateException","httpStatus":null,"severity":"error","filePath":"extensions/security/deployment/src/main/java/io/quarkus/security/deployment/PermissionSecurityChecks.java","lineNumber":447,"sourceCode":"\n        PermissionSecurityChecksBuilder gatherPermissionsAllowedAnnotations(\n                Map<MethodInfo, AnnotationInstance> alreadyCheckedMethods,\n                Map<ClassInfo, AnnotationInstance> alreadyCheckedClasses,\n                List<AnnotationInstance> additionalClassInstances,\n                Predicate<MethodInfo> hasAdditionalSecurityAnnotations) {\n\n            List<PermissionKey> cache = new ArrayList<>();\n            Map<MethodInfo, List<List<PermissionKey>>> classMethodToPermissionKeys = new HashMap<>();\n            for (AnnotationInstance instance : permissionInstances) {\n\n                AnnotationTarget target = instance.target();\n                if (target.kind() == AnnotationTarget.Kind.METHOD) {\n                    // method annotation\n                    final MethodInfo methodInfo = target.asMethod();\n\n                    // we don't allow combining @PermissionsAllowed with other security annotations as @DenyAll, ...\n                    if (alreadyCheckedMethods.containsKey(methodInfo) || hasAdditionalSecurityAnnotations.test(methodInfo)) {\n                        throw new IllegalStateException(\n                                String.format(\"Method %s of class %s is annotated with multiple security annotations\",\n                                        methodInfo.name(), methodInfo.declaringClass()));\n                    }\n\n                    gatherPermissionKeys(instance, methodInfo, cache, targetToPermissionKeys);\n                } else {\n                    // class annotation\n\n                    // add permissions for the class annotation if respective method haven't already been annotated\n                    if (target.kind() == AnnotationTarget.Kind.CLASS) {\n                        final ClassInfo clazz = target.asClass();\n\n                        // ignore PermissionsAllowedInterceptor in security module\n                        // we also need to check string as long as duplicate \"PermissionsAllowedInterceptor\" exists\n                        // in RESTEasy Reactive, however this workaround should be removed when the interceptor is dropped\n                        if (isPermissionsAllowedInterceptor(clazz)) {\n                            continue;\n                        }","sourceCodeStart":429,"sourceCodeEnd":465,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/security/deployment/src/main/java/io/quarkus/security/deployment/PermissionSecurityChecks.java#L429-L465","documentation":"A method is annotated with @PermissionsAllowed together with another security annotation such as @DenyAll, @PermitAll, or @RolesAllowed. Quarkus does not allow combining @PermissionsAllowed with other security annotations on the same method because the authorization semantics would be ambiguous, so the build fails with an IllegalStateException.","triggerScenarios":"Annotating one method with both @PermissionsAllowed and @DenyAll/@PermitAll/@RolesAllowed/@Authenticated; detected in gatherPermissionsAllowedAnnotations via alreadyCheckedMethods or hasAdditionalSecurityAnnotations.","commonSituations":"Applying class-level security defaults then adding method-level @PermissionsAllowed on top of a leftover @RolesAllowed; stacking annotations while experimenting with the security API.","solutions":["Remove the conflicting security annotation (@RolesAllowed, @DenyAll, @PermitAll, etc.) from the method, keeping only @PermissionsAllowed","Express the combined policy inside a single @PermissionsAllowed expression or permission checker","Move the broad policy to class level and keep method-level only @PermissionsAllowed"],"exampleFix":"// before\n@RolesAllowed(\"admin\")\n@PermissionsAllowed(\"book:delete\")\npublic void delete(Long id) {...}\n\n// after\n@PermissionsAllowed(\"book:delete\")\npublic void delete(Long id) {...}","handlingStrategy":"validation","validationCode":"for (Annotation a : MyResource.class.getMethod(\"delete\", Long.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":["One security annotation per method — prefer @PermissionsAllowed exclusively","Search the class for leftover @RolesAllowed/@DenyAll before adding @PermissionsAllowed","Codify the rule with an ArchUnit test"],"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"}