{"record":{"id":"8fec8ebcae352032","repo":"quarkusio/quarkus","slug":"multiple-instances-of-non-repeatable-interceptor-b","errorCode":null,"errorMessage":"Multiple instances of non-repeatable interceptor binding annotation ","messagePattern":"Multiple instances of non-repeatable interceptor binding annotation ","errorType":"validation","errorClass":"DefinitionException","httpStatus":null,"severity":"error","filePath":"independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Interceptors.java","lineNumber":126,"sourceCode":"                // don't validate @Repeatable interceptor bindings, repeatability is their entire point\n                continue;\n            }\n\n            List<AnnotationValue> seenValues = seenBindings.get(name);\n            if (seenValues != null) {\n                // interceptor binding of the same type already seen\n                // all annotation members (except nonbinding) must have equal values\n                ClassInfo declaration = beanDeployment.getInterceptorBinding(name);\n                Set<String> nonBindingMembers = beanDeployment.getInterceptorNonbindingMembers(name);\n\n                for (AnnotationValue value : seenValues) {\n                    if (declaration.method(value.name()).hasDeclaredAnnotation(DotNames.NONBINDING)\n                            || nonBindingMembers.contains(value.name())) {\n                        continue;\n                    }\n\n                    if (!value.equals(binding.valueWithDefault(index, value.name()))) {\n                        throw new DefinitionException(\"Multiple instances of non-repeatable interceptor binding annotation \"\n                                + name + \" with different member values on class \" + targetClass);\n                    }\n                }\n            } else {\n                // interceptor binding of that type not seen yet, just remember it\n                seenBindings.put(name, binding.valuesWithDefaults(index));\n            }\n        }\n    }\n\n    private static void checkInterceptorFieldsAndMethods(ClassInfo interceptorClass, BeanDeployment beanDeployment) {\n        ClassInfo aClass = interceptorClass;\n        while (aClass != null) {\n            for (MethodInfo method : aClass.methods()) {\n                if (beanDeployment.hasAnnotation(method, DotNames.PRODUCES)) {\n                    throw new DefinitionException(\"Interceptor declares a producer method: \" + interceptorClass);\n                }\n                // the following 3 checks rely on the annotation store returning parameter annotations for methods","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Interceptors.java#L108-L144","documentation":"ArC throws this DefinitionException when a class (the interceptor class or a bean class) declares the same non-repeatable interceptor binding annotation more than once — directly and/or via inheritance — with different member values. Interceptor bindings must be unambiguous: for a non-repeatable binding type, all occurrences must resolve to identical member values (defaults included). Detected at build time.","triggerScenarios":"The same binding annotation appears multiple times on a class hierarchy (e.g. on both the interceptor class and its superclass, or repeated via inheritance) with non-binding member values that differ after applying annotation-member defaults. Non-binding and @NonBinding members are excluded from the comparison.","commonSituations":"Subclassing an interceptor or bean that already carries a binding annotation and re-annotating the subclass with different member values (e.g. @Logged(level=\"INFO\") on the parent, @Logged(level=\"DEBUG\") on the child); changing member defaults between versions.","solutions":["Make the member values identical in all declarations of the binding annotation on the class hierarchy, or remove the duplicate declaration.","Mark the differing member with @NonBinding if its value should not participate in binding equality.","Restructure so the binding appears only once (e.g. only on the leaf class), and consider @Repeatable bindings if multiple distinct bindings are actually wanted."],"exampleFix":"// before\n@Logged(level = \"INFO\") class Base { }\n@Logged(level = \"DEBUG\") class Child extends Base { }\n// after\n@Logged(level = \"DEBUG\") class Child extends Base { } // remove annotation from Base, or make values equal","handlingStrategy":"validation","validationCode":"// Check the class hierarchy for repeated non-repeatable bindings with conflicting members\njava.util.Map<Class<?>, java.lang.annotation.Annotation> seen = new java.util.HashMap<>();\nfor (Class<?> c = Child.class; c != null && c != Object.class; c = c.getSuperclass()) {\n    for (java.lang.annotation.Annotation a : c.getAnnotations()) {\n        if (a.annotationType().isAnnotationPresent(jakarta.interceptor.InterceptorBinding.class)\n            && !a.annotationType().isAnnotationPresent(java.lang.annotation.Repeatable.class)) {\n            java.lang.annotation.Annotation prev = seen.putIfAbsent(a.annotationType(), a);\n            if (prev != null && !prev.equals(a)) {\n                throw new IllegalStateException(\"Conflicting binding values: \" + prev + \" vs \" + a);\n            }\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Declare each non-repeatable binding at most once across the hierarchy, with identical member values","Use @NonBinding on members whose values should not affect binding equality","Make bindings @Repeatable when multiple distinct bindings of the same type are intended"],"tags":["cdi","quarkus","arc","interceptor-binding","inheritance"],"backgroundTag":"conflicting-interceptor-binding-values","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"}