{"record":{"id":"69f1b8961f15e743","repo":"quarkusio/quarkus","slug":"interceptor-binding-was-used-repeatedly-but-is-no","errorCode":null,"errorMessage":"Interceptor binding  was used repeatedly but is not @Repeatable","messagePattern":"Interceptor binding  was used repeatedly but is not @Repeatable","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/InterceptorBindings.java","lineNumber":51,"sourceCode":"            verifyInterceptorBinding(interceptorBindings[0].annotationType());\n        } else {\n            Map<Class<? extends Annotation>, Integer> timesQualifierWasSeen = new HashMap<>();\n            for (Annotation interceptorBinding : interceptorBindings) {\n                verifyInterceptorBinding(interceptorBinding.annotationType());\n                timesQualifierWasSeen.compute(interceptorBinding.annotationType(), TimesSeenBiFunction.INSTANCE);\n            }\n            checkInterceptorBindingsForDuplicates(timesQualifierWasSeen);\n        }\n    }\n\n    // in various cases, specification requires to check interceptor bindings for duplicates and throw IAE\n    private static void checkInterceptorBindingsForDuplicates(Map<Class<? extends Annotation>, Integer> timesSeen) {\n        timesSeen.forEach(InterceptorBindings::checkInterceptorBindingsForDuplicates);\n    }\n\n    private static void checkInterceptorBindingsForDuplicates(Class<? extends Annotation> annClass, Integer timesSeen) {\n        if (timesSeen > 1 && !annClass.isAnnotationPresent(Repeatable.class)) {\n            throw new IllegalArgumentException(\"Interceptor binding \" + annClass\n                    + \" was used repeatedly but is not @Repeatable\");\n        }\n    }\n\n    private void verifyInterceptorBinding(Class<? extends Annotation> annotationType) {\n        if (!allInterceptorBindings.contains(annotationType.getName())) {\n            throw new IllegalArgumentException(\"Annotation is not a registered interceptor binding: \" + annotationType);\n        }\n    }\n\n    private static class TimesSeenBiFunction implements BiFunction<Class<? extends Annotation>, Integer, Integer> {\n        private static final TimesSeenBiFunction INSTANCE = new TimesSeenBiFunction();\n\n        @Override\n        public Integer apply(Class<? extends Annotation> k, Integer v) {\n            return v == null ? 1 : v + 1;\n        }\n    }","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/InterceptorBindings.java#L33-L69","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Remove the duplicate binding annotation from the call — one instance is enough","Make the binding annotation @Repeatable with a proper container annotation if multiple occurrences are meaningful","Merge the binding's members into a single annotation instance (e.g. one @Foo with multiple values) instead of repeating it"],"exampleFix":"// before\nintercept(m, new Secured.Literal(\"read\"), new Secured.Literal(\"write\")); // @Secured not @Repeatable\n// after\nintercept(m, new Secured.Literal(\"read\", \"write\")); // single instance, multiple values","handlingStrategy":"validation","validationCode":"static void requireNoDuplicateBindings(Annotation... bindings) {\n    Set<Class<? extends Annotation>> seen = new HashSet<>();\n    for (Annotation b : bindings) {\n        if (!seen.add(b.annotationType())\n            && !b.annotationType().isAnnotationPresent(Repeatable.class)) {\n            throw new IllegalArgumentException(b.annotationType() + \" used twice but is not @Repeatable\");\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    intercept(method, bindings);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"used repeatedly but is not @Repeatable\")) {\n        throw new IllegalStateException(\"Deduplicate bindings or make the annotation @Repeatable\", e);\n    }\n    throw e;\n}","preventionTips":["Before passing bindings, deduplicate by annotation type unless it's @Repeatable","Prefer encoding multiple values in a single binding instance's members","Document which custom bindings are repeatable to avoid misuse"],"tags":["cdi","arc","interceptors","annotations"],"backgroundTag":"non-repeatable-interceptor-binding","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"}