quarkusio/quarkus · error · java.lang.IllegalArgumentException

The qualifier ${aClass} was used repeatedly but it is not an

Error message

The qualifier ${aClass} was used repeatedly but it is not annotated with @java.lang.annotation.Repeatable

What it means

When building qualifier sets, Qualifiers counts how often each qualifier annotation appears. If the same qualifier class is supplied more than once and that annotation is not meta-annotated with @Repeatable, the combination is invalid per CDI semantics and IllegalArgumentException is thrown.

Source

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

            Map<Class<? extends Annotation>, Integer> timesQualifierWasSeen = new HashMap<>();
            for (Annotation qualifier : qualifiers) {
                verifyQualifier(qualifier.annotationType());
                timesQualifierWasSeen.compute(qualifier.annotationType(), TimesSeenBiFunction.INSTANCE);
            }
            checkQualifiersForDuplicates(timesQualifierWasSeen);
        }
    }

    // in various cases, specification requires to check qualifiers for duplicates and throw IAE
    private static void checkQualifiersForDuplicates(Map<Class<? extends Annotation>, Integer> timesQualifierSeen) {
        for (Entry<Class<? extends Annotation>, Integer> entry : timesQualifierSeen.entrySet()) {
            checkQualifiersForDuplicates(entry.getKey(), entry.getValue());
        }
    }

    private static void checkQualifiersForDuplicates(Class<? extends Annotation> aClass, Integer times) {
        if (times > 1 && (aClass.getAnnotation(Repeatable.class) == null)) {
            throw new IllegalArgumentException("The qualifier " + aClass + " was used repeatedly " +
                    "but it is not annotated with @java.lang.annotation.Repeatable");
        }
    }

    boolean hasQualifiers(Set<Annotation> beanQualifiers, Annotation... requiredQualifiers) {
        for (Annotation qualifier : requiredQualifiers) {
            if (!hasQualifier(beanQualifiers, qualifier)) {
                return false;
            }
        }
        return true;
    }

    boolean hasQualifier(Iterable<Annotation> qualifiers, Annotation requiredQualifier) {

        Class<? extends Annotation> requiredQualifierClass = requiredQualifier.annotationType();
        Method[] members = requiredQualifierClass.getDeclaredMethods();

View on GitHub (pinned to e1c734241f)

Solutions

  1. Pass each qualifier only once — duplicates are redundant since qualifiers match conjunctively.
  2. If repetition is intentional, add @Repeatable to the qualifier annotation (with a container annotation) — though the CDI runtime here rejects duplicates regardless.
  3. Deduplicate the qualifier array before calling select()/instance() (e.g. new LinkedHashSet<>(Arrays.asList(qualifiers))).
  4. Use distinct qualifiers (e.g. @Named values) if you need multiple constraints.

Example fix

// before
Instance<Foo> i = Arc.container().select(Foo.class, new Qual1L(), new Qual1L());
// after
Instance<Foo> i = Arc.container().select(Foo.class, new Qual1L());
Defensive patterns

Strategy: validation

Validate before calling

Set<Class<? extends Annotation>> seen = new LinkedHashSet<>();
for (Annotation q : qualifiers) {
    if (!seen.add(q.annotationType())) {
        throw new IllegalArgumentException("Duplicate qualifier " + q.annotationType() + " (not repeatable)");
    }
}

Type guard

boolean allDistinct(Annotation... qs) {
    return Arrays.stream(qs).map(Annotation::annotationType).distinct().count() == qs.length;
}

Try / catch

try {
    return Arc.container().select(type, qualifiers);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("not annotated with @java.lang.annotation.Repeatable")) {
        return Arc.container().select(type, Arrays.stream(qualifiers).distinct().toArray(Annotation[]::new));
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling Arc.container().instance(Foo.class, new Literal(), new Literal()) or any select()/qualifier API passing the same non-repeatable qualifier annotation instance/class twice.

Common situations: Programmatic lookup code that accumulates qualifiers in a loop and appends duplicates; refactored code merging qualifier arrays; misunderstanding @Repeatable requirements when multiple identical qualifiers are meant to AND together.

Related errors


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