quarkusio/quarkus · error · java.lang.IllegalArgumentException
Annotation is not a registered qualifier: ${annotationType}
Error message
Annotation is not a registered qualifier: ${annotationType} What it means
Qualifiers.verify() checks that every annotation passed to qualifier-matching APIs is one of the qualifiers registered in the container's deployment. If annotationType is not in allQualifiers, IllegalArgumentException is thrown. This catches lookups using annotations that were never declared as CDI qualifiers.
Source
Thrown at independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/Qualifiers.java:154
return false;
}
}
return true;
}
private static Object invoke(Method method, Object instance) {
try {
method.setAccessible(true);
return method.invoke(instance);
} catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(
"Error checking value of member method " + method.getName() + " on " + method.getDeclaringClass(), e);
}
}
private void verifyQualifier(Class<? extends Annotation> annotationType) {
if (!allQualifiers.contains(annotationType.getName())) {
throw new IllegalArgumentException("Annotation is not a registered qualifier: " + annotationType);
}
}
private static class TimesSeenBiFunction implements BiFunction<Class<? extends Annotation>, Integer, Integer> {
private static final TimesSeenBiFunction INSTANCE = new TimesSeenBiFunction();
private TimesSeenBiFunction() {
}
@Override
public Integer apply(Class<? extends Annotation> k, Integer v) {
return (v == null) ? 1 : (v + 1);
}
}
}
View on GitHub (pinned to e1c734241f)
Solutions
- Add @jakarta.inject.Qualifier (with @Retention(RUNTIME)) to the annotation type and rebuild so it's indexed.
- Ensure the annotation's package is part of the indexed application/extension (Jandex index present).
- Check the annotation name — you may be using a similarly named non-qualifier annotation by mistake.
- After upgrading a library, verify the qualifier still exists and is registered; update the lookup accordingly.
Example fix
// before
@Retention(RUNTIME)
public @interface Cool { } // missing @Qualifier
// after
@Qualifier
@Retention(RUNTIME)
public @interface Cool { } Defensive patterns
Strategy: validation
Validate before calling
static void requireQualifier(Class<? extends Annotation> a) {
if (!a.isAnnotationPresent(jakarta.inject.Qualifier.class)) {
throw new IllegalArgumentException(a + " is missing @Qualifier; it cannot be used in select()");
}
} Type guard
boolean isCdiQualifier(Class<? extends Annotation> a) {
return a.isAnnotationPresent(jakarta.inject.Qualifier.class);
} Try / catch
try {
return Arc.container().instance(type, qualifier);
} catch (IllegalArgumentException e) {
if (e.getMessage().startsWith("Annotation is not a registered qualifier")) {
throw new IllegalStateException("Add @Qualifier to " + qualifier.annotationType() + " and rebuild", e);
}
throw e;
} Prevention
- Meta-annotate every custom lookup annotation with @Qualifier
- Verify the annotation's module is indexed by Jandex
- After library upgrades, confirm qualifiers still exist before lookup
- Catch typos early by centralizing qualifier literals in one place
When it happens
Trigger: Passing a plain (non-@Qualifier) annotation, or a qualifier from a library not part of the indexed deployment, into Arc.container().instance()/select() or Instance.select(...) as a qualifier argument.
Common situations: Typos or a forgotten @Qualifier meta-annotation on a custom annotation; using an annotation from a module not indexed by Jandex; lookups written against a qualifier that was removed/renamed in an upgrade.
Related errors
- Annotation does not have @Retention(RUNTIME):
- Annotation class not available:
- Value is not set for %s.%s(). Most probably an older version
- Class of nested annotation missing
- Array component kind is
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/983a3c19b616a7f7.
Report an issue: GitHub.