quarkusio/quarkus · error · IllegalArgumentException

Not a qualifier:

Error message

Not a qualifier: 

What it means

ReceiverDefinitionImpl.setQualifiers validates that every supplied CDI annotation is actually a qualifier registered in the bean container. Passing a plain annotation (not a @Qualifier) would silently produce broken bean resolution, so it throws IllegalArgumentException.

Source

Thrown at extensions/signals/runtime/src/main/java/io/quarkus/signals/runtime/impl/ReceiverDefinitionImpl.java:41

    private final Function<CallbackReceiver<SIGNAL, RESPONSE>, Receivers.Registration> registerFun;
    private final BeanContainer beanContainer;
    private final Type signalType;
    private Set<Annotation> qualifiers = Set.of();
    private ExecutionModel executionModel = ExecutionModel.BLOCKING;

    public ReceiverDefinitionImpl(Type signalType, BeanContainer beanContainer,
            Function<CallbackReceiver<SIGNAL, RESPONSE>, Receivers.Registration> registerFun) {
        this.signalType = signalType;
        this.beanContainer = beanContainer;
        this.registerFun = registerFun;
    }

    @Override
    public Receivers.ReceiverDefinition<SIGNAL> setQualifiers(Annotation... qualifiers) {
        for (Annotation qualifier : qualifiers) {
            if (!beanContainer.isQualifier(qualifier.annotationType())) {
                throw new IllegalArgumentException("Not a qualifier: " + qualifier.annotationType().getName());
            }
        }
        this.qualifiers = Set.of(qualifiers);
        return this;
    }

    @Override
    public Receivers.ReceiverDefinition<SIGNAL> setExecutionModel(ExecutionModel executionModel) {
        this.executionModel = Objects.requireNonNull(executionModel);
        return this;
    }

    @Override
    public Registration notify(Consumer<SignalContext<SIGNAL>> callback) {
        Objects.requireNonNull(callback);
        @SuppressWarnings("unchecked")
        CallbackReceiver<SIGNAL, RESPONSE> receiver = (CallbackReceiver<SIGNAL, RESPONSE>) new CallbackReceiver<>(
                signalType, qualifiers, void.class, executionModel,

View on GitHub (pinned to e1c734241f)

Solutions

  1. Only pass annotations meta-annotated with @jakarta.inject.Qualifier.
  2. Check the annotation's package/API (jakarta.enterprise vs javax or other) — use the CDI one the container knows.
  3. Register the custom qualifier properly or use a built-in qualifier like @Named or @Identifier.

Example fix

// before
@Retention(RUNTIME) @interface MyQ {}  // not a qualifier
setQualifiers(new MyQ() { ... });

// after
@Qualifier @Retention(RUNTIME) @interface MyQ {}
setQualifiers(new MyQ() { ... });
Defensive patterns

Strategy: validation

Validate before calling

for (Annotation a : qualifiers) {
    if (!a.annotationType().isAnnotationPresent(jakarta.inject.Qualifier.class)) {
        throw new IllegalArgumentException(a.annotationType() + " is not a CDI qualifier");
    }
}

Prevention

When it happens

Trigger: Calling receiverDefinition.setQualifiers(annotation...) with an annotation type not recognized as a CDI qualifier by the ArC bean container.

Common situations: Passing @jakarta.inject.Qualifier-less annotations, using annotations from the wrong injection API, or forgetting a @Qualifier meta-annotation on a custom annotation.

Related errors


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