quarkusio/quarkus · error · DefinitionException
Multiple instances of non-repeatable interceptor binding ann
Error message
Multiple instances of non-repeatable interceptor binding annotation
What it means
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.
Source
Thrown at independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Interceptors.java:126
// don't validate @Repeatable interceptor bindings, repeatability is their entire point
continue;
}
List<AnnotationValue> seenValues = seenBindings.get(name);
if (seenValues != null) {
// interceptor binding of the same type already seen
// all annotation members (except nonbinding) must have equal values
ClassInfo declaration = beanDeployment.getInterceptorBinding(name);
Set<String> nonBindingMembers = beanDeployment.getInterceptorNonbindingMembers(name);
for (AnnotationValue value : seenValues) {
if (declaration.method(value.name()).hasDeclaredAnnotation(DotNames.NONBINDING)
|| nonBindingMembers.contains(value.name())) {
continue;
}
if (!value.equals(binding.valueWithDefault(index, value.name()))) {
throw new DefinitionException("Multiple instances of non-repeatable interceptor binding annotation "
+ name + " with different member values on class " + targetClass);
}
}
} else {
// interceptor binding of that type not seen yet, just remember it
seenBindings.put(name, binding.valuesWithDefaults(index));
}
}
}
private static void checkInterceptorFieldsAndMethods(ClassInfo interceptorClass, BeanDeployment beanDeployment) {
ClassInfo aClass = interceptorClass;
while (aClass != null) {
for (MethodInfo method : aClass.methods()) {
if (beanDeployment.hasAnnotation(method, DotNames.PRODUCES)) {
throw new DefinitionException("Interceptor declares a producer method: " + interceptorClass);
}
// the following 3 checks rely on the annotation store returning parameter annotations for methodsView on GitHub (pinned to e1c734241f)
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.
Example fix
// before
@Logged(level = "INFO") class Base { }
@Logged(level = "DEBUG") class Child extends Base { }
// after
@Logged(level = "DEBUG") class Child extends Base { } // remove annotation from Base, or make values equal Defensive patterns
Strategy: validation
Validate before calling
// Check the class hierarchy for repeated non-repeatable bindings with conflicting members
java.util.Map<Class<?>, java.lang.annotation.Annotation> seen = new java.util.HashMap<>();
for (Class<?> c = Child.class; c != null && c != Object.class; c = c.getSuperclass()) {
for (java.lang.annotation.Annotation a : c.getAnnotations()) {
if (a.annotationType().isAnnotationPresent(jakarta.interceptor.InterceptorBinding.class)
&& !a.annotationType().isAnnotationPresent(java.lang.annotation.Repeatable.class)) {
java.lang.annotation.Annotation prev = seen.putIfAbsent(a.annotationType(), a);
if (prev != null && !prev.equals(a)) {
throw new IllegalStateException("Conflicting binding values: " + prev + " vs " + a);
}
}
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Interceptor has no bindings:
- Quarkus does not support CDI Full @Specializes annotation; t
- IllegalStateException wrapping ClassNotFoundException for ge
- Unable to derive the logger name at ${injectionPoint}
- Improper integration of '${LogFilterFactory.class.getName()}
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/8fec8ebcae352032.
Report an issue: GitHub.