{"record":{"id":"bd78969f9dfb6bb0","repo":"quarkusio/quarkus","slug":"only-one-of-the-annotations-annotations-can-be","errorCode":null,"errorMessage":"Only one of the '<annotations>' annotations can be applied on the '<class>' class","messagePattern":"Only one of the '<annotations>' annotations can be applied on the '<class>' class","errorType":"validation","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/HttpSecurityProcessor.java","lineNumber":858,"sourceCode":"                for (AnnotationInstance annotation : annotationInstances) {\n                    if (annotation.target().kind() != appliesTo) {\n                        continue;\n                    }\n                    if (annotation.target().kind() == AnnotationTarget.Kind.CLASS) {\n                        ClassInfo interceptedClass = annotation.target().asClass();\n                        if (interceptedClass.isAnnotation()) {\n                            // currently we don't support meta-annotations\n                            // this is the easiest way to avoid detecting @HttpAuthenticationMechanism on @BasicAuthentication\n                            continue;\n                        }\n\n                        if (hasClassLevelSecurity.test(interceptedClass)) {\n                            // endpoint can only be annotated with one of @Basic, @Form, ...\n                            // however combining @CodeFlow and @Tenant is supported\n                            var appliedBindings = cache.computeIfAbsent(interceptedClass, a -> new ArrayList<>());\n                            if (appliedBindings.contains(interceptorBinding)) {\n                                if (!interceptorBinding.allowToRepeatThisInterceptorBinding()) {\n                                    throw new RuntimeException(\n                                            \"Only one of the '%s' annotations can be applied on the '%s' class\".formatted(\n                                                    Arrays.toString(interceptorBinding.getAnnotationBindings()),\n                                                    interceptedClass));\n                                }\n                            } else {\n                                appliedBindings.add(interceptorBinding);\n                            }\n\n                            // don't apply security interceptor on individual methods, but on the class-level instead\n                            bindingValueToInterceptedClasses\n                                    .computeIfAbsent(interceptorBinding.getBindingValue(annotation, annotationBinding,\n                                            interceptedClass), s -> new HashSet<>())\n                                    .add(interceptedClass.name().toString());\n                            continue;\n                        }\n\n                        for (MethodInfo method : interceptedClass.methods()) {\n                            if (hasProperEndpointModifiers(method)) {","sourceCodeStart":840,"sourceCodeEnd":876,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/HttpSecurityProcessor.java#L840-L876","documentation":"A class (endpoint) may only carry one of the mutually exclusive HTTP security annotations such as @Basic, @Form, @BearerAuth, etc. Combining two of these on the same class is ambiguous — only one auth mechanism can be selected per endpoint — so the build fails. @CodeFlow and @Tenant are the exceptions and may be combined with others.","triggerScenarios":"Annotating the same endpoint class with two different auth mechanism annotations (e.g. both @Basic and @Form), where the binding does not allow repetition.","commonSituations":"Merging code from branches where different developers chose different mechanisms; copy-pasting security annotations between classes without removing the old one; misunderstanding which annotations are mutually exclusive.","solutions":["Keep only one auth mechanism annotation on the class and delete the other","If both behaviors are needed, use configuration-based policy (quarkus.http.auth.permission) instead","Move the mechanism choice to individual endpoint methods if different endpoints need different mechanisms"],"exampleFix":"// before\n@Basic\n@Form\npublic class UserResource { ... }\n// after\n@Basic\npublic class UserResource { ... }","handlingStrategy":"validation","validationCode":"long count = Arrays.stream(Resource.class.getAnnotations())\n    .map(Annotation::annotationType)\n    .filter(t -> Set.of(Basic.class, Form.class, BearerAuth.class).contains(t))\n    .count();\nif (count > 1) throw new IllegalStateException(\"Only one auth mechanism annotation allowed on class\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pick one auth mechanism per endpoint class","Remember @CodeFlow and @Tenant are the only combinable ones","Prefer quarkus.http.auth.permission config rules for layered policies"],"tags":["quarkus","build-time","security","annotation"],"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"}