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
- Call select() only with a fully concrete TypeLiteral (replace T with a real type at the call site)
- Move the select() call out of the generic context and into a non-generic method that knows the concrete type
- Pass the resolved Class/Type as a method argument from a non-generic caller and build the TypeLiteral from it
- 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
- Never pass TypeLiterals built from open type variables inside generic classes/methods
- Keep event.select() calls in non-generic code where concrete types are known
- Add a unit test that selects every event type used in the app
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
- Event injection point can never be raw type - please specify
- CDI event payload cannot contain unresolved type variable; f
- InterceptionProxy parameter must be a parameterized type: ${
- Producer field type is a parameterized type with a type vari
- Declaring class of a managed bean is generic, its scope must
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/7c5da4a18b3f03a0.
Report an issue: GitHub.