quarkusio/quarkus · error · IllegalArgumentException

Event#select(TypeLiteral, Annotation...) cannot be used with

Error message

Event#select(TypeLiteral, Annotation...) cannot be used with type variable parameter

What it means

ArC (Quarkus's CDI implementation) rejects Event#select(TypeLiteral, Annotation...) when the given TypeLiteral's type still contains an unresolved type variable (e.g. select(new TypeLiteral<List<T>>(){}) where T is open). The CDI specification forbids this because the container could not determine a concrete event type to match observers. It is thrown eagerly from select() to fail fast.

Source

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

    }

    @Override
    public <U extends T> Event<U> select(Class<U> subtype, Annotation... qualifiers) {
        if (Types.containsTypeVariable(subtype)) {
            throw new IllegalArgumentException(
                    "Event#select(Class<U>, Annotation...) cannot be used with type variable parameter");
        }
        ArcContainerImpl.instance().registeredQualifiers.verify(qualifiers);
        Set<Annotation> mergerdQualifiers = new HashSet<>(this.qualifiers);
        Collections.addAll(mergerdQualifiers, qualifiers);
        return new EventImpl<U>(subtype, mergerdQualifiers, injectionPoint);
    }

    @Override
    public <U extends T> Event<U> select(TypeLiteral<U> subtype, Annotation... qualifiers) {
        ArcContainerImpl.instance().registeredQualifiers.verify(qualifiers);
        if (Types.containsTypeVariable(subtype.getType())) {
            throw new IllegalArgumentException(
                    "Event#select(TypeLiteral, Annotation...) cannot be used with type variable parameter");
        }
        Set<Annotation> mergerdQualifiers = new HashSet<>(this.qualifiers);
        Collections.addAll(mergerdQualifiers, qualifiers);
        return new EventImpl<U>(subtype.getType(), mergerdQualifiers, injectionPoint);
    }

    private Notifier<? super T> createNotifier(Class<?> runtimeType) {
        Type eventType = getEventType(runtimeType);
        return createNotifier(runtimeType, eventType, qualifiers, ArcContainerImpl.unwrap(Arc.requireContainer()),
                injectionPoint);
    }

    static <T> Notifier<T> createNotifier(Class<?> runtimeType, Type eventType, Set<Annotation> qualifiers,
            ArcContainerImpl container, InjectionPoint injectionPoint) {
        return createNotifier(runtimeType, eventType, qualifiers, container, !Arc.requireContainer().strictCompatibility(),
                injectionPoint);
    }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Call select() only with a fully concrete TypeLiteral (replace T with a real type at the call site)
  2. Move the select() call out of the generic context and into a non-generic method that knows the concrete type
  3. Pass the resolved Class/Type as a method argument from a non-generic caller and build the TypeLiteral from it
  4. Capture the concrete type with an anonymous subclass of TypeLiteral at a point where the type is known

Example fix

// before (T unresolved)
public <T> void fireSub(Event<T> event) {
    event.select(new TypeLiteral<Wrapper<T>>() {});
}
// after (concrete type)
event.select(new TypeLiteral<Wrapper<String>>() {});
Defensive patterns

Strategy: validation

Validate before calling

static <U> TypeLiteral<U> requireConcrete(TypeLiteral<U> literal) {
    if (io.quarkus.arc.impl.Types.containsTypeVariable(literal.getType())) {
        throw new IllegalArgumentException("TypeLiteral must be fully concrete: " + literal.getType());
    }
    return literal;
}
// usage: event.select(requireConcrete(new TypeLiteral<List<String>>() {}));

Type guard

static boolean isConcrete(Type t) {
    return !io.quarkus.arc.impl.Types.containsTypeVariable(t);
}

Try / catch

try {
    event.select(literal, qualifiers);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("type variable")) {
        throw new IllegalStateException("Use a concrete TypeLiteral; got generic type", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling event.select(new TypeLiteral<...>(){...}) where the TypeLiteral's type parameter references an unbound type variable, typically inside a generic class or generic method where the class's type parameter leaks into the literal.

Common situations: Helper/utility methods that wrap Event<T> and forward select() with the class's own type variable; generic DAO or service base classes selecting subtypes of a generic event payload.

Related errors


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