quarkusio/quarkus · error · IllegalArgumentException

Interceptor binding was used repeatedly but is not @Repeata

Error message

Interceptor binding  was used repeatedly but is not @Repeatable

What it means

ArC validates interceptor binding annotations passed to APIs like InterceptedCall/intercept(). If the same binding annotation type appears more than once and that annotation is not @Repeatable, the CDI spec requires IllegalArgumentException. Non-repeatable bindings can only appear once in a binding set.

Source

Thrown at independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/InterceptorBindings.java:51

            verifyInterceptorBinding(interceptorBindings[0].annotationType());
        } else {
            Map<Class<? extends Annotation>, Integer> timesQualifierWasSeen = new HashMap<>();
            for (Annotation interceptorBinding : interceptorBindings) {
                verifyInterceptorBinding(interceptorBinding.annotationType());
                timesQualifierWasSeen.compute(interceptorBinding.annotationType(), TimesSeenBiFunction.INSTANCE);
            }
            checkInterceptorBindingsForDuplicates(timesQualifierWasSeen);
        }
    }

    // in various cases, specification requires to check interceptor bindings for duplicates and throw IAE
    private static void checkInterceptorBindingsForDuplicates(Map<Class<? extends Annotation>, Integer> timesSeen) {
        timesSeen.forEach(InterceptorBindings::checkInterceptorBindingsForDuplicates);
    }

    private static void checkInterceptorBindingsForDuplicates(Class<? extends Annotation> annClass, Integer timesSeen) {
        if (timesSeen > 1 && !annClass.isAnnotationPresent(Repeatable.class)) {
            throw new IllegalArgumentException("Interceptor binding " + annClass
                    + " was used repeatedly but is not @Repeatable");
        }
    }

    private void verifyInterceptorBinding(Class<? extends Annotation> annotationType) {
        if (!allInterceptorBindings.contains(annotationType.getName())) {
            throw new IllegalArgumentException("Annotation is not a registered interceptor binding: " + annotationType);
        }
    }

    private static class TimesSeenBiFunction implements BiFunction<Class<? extends Annotation>, Integer, Integer> {
        private static final TimesSeenBiFunction INSTANCE = new TimesSeenBiFunction();

        @Override
        public Integer apply(Class<? extends Annotation> k, Integer v) {
            return v == null ? 1 : v + 1;
        }
    }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Remove the duplicate binding annotation from the call — one instance is enough
  2. Make the binding annotation @Repeatable with a proper container annotation if multiple occurrences are meaningful
  3. Merge the binding's members into a single annotation instance (e.g. one @Foo with multiple values) instead of repeating it

Example fix

// before
intercept(m, new Secured.Literal("read"), new Secured.Literal("write")); // @Secured not @Repeatable
// after
intercept(m, new Secured.Literal("read", "write")); // single instance, multiple values
Defensive patterns

Strategy: validation

Validate before calling

static void requireNoDuplicateBindings(Annotation... bindings) {
    Set<Class<? extends Annotation>> seen = new HashSet<>();
    for (Annotation b : bindings) {
        if (!seen.add(b.annotationType())
            && !b.annotationType().isAnnotationPresent(Repeatable.class)) {
            throw new IllegalArgumentException(b.annotationType() + " used twice but is not @Repeatable");
        }
    }
}

Try / catch

try {
    intercept(method, bindings);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("used repeatedly but is not @Repeatable")) {
        throw new IllegalStateException("Deduplicate bindings or make the annotation @Repeatable", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling intercept(...) or other ArcContainer/Instance APIs with the same non-repeatable binding twice, e.g. intercept(myMethod, new Foo.Literal("a"), new Foo.Literal("b")) where @Foo is not @Repeatable.

Common situations: Assuming all interceptor bindings are repeatable like some built-in ones; copying a binding array that accidentally contains a duplicate; generated code emitting the binding twice.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/69f1b8961f15e743. Report an issue: GitHub.