quarkusio/quarkus · error · DefinitionException

Injected @Intercepted Bean<?> has to use unbound wildcard as

Error message

Injected @Intercepted Bean<?> has to use unbound wildcard as its type parameter. Problematic injection point: ${injectionPointInfo.getTargetInfo()}

What it means

When Bean<T> is injected with the @Intercepted qualifier, the CDI spec mandates the type parameter be an unbound wildcard (Bean<?>). ArC validates the required type is a parameterized type with exactly one argument — a wildcard with no super bound and java.lang.Object extends bound — and throws this DefinitionException otherwise.

Source

Thrown at independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Injection.java:144

                    throw new DefinitionException(
                            "Type of injected Bean<T> does not match the type of the bean declaring the " +
                                    "injection point. Problematic injection point: " + injectionPointInfo.getTargetInfo());
                }
            }
        }
        if (beanType == BeanType.INTERCEPTOR) {
            // the injection point is a field, an initializer method parameter or a bean constructor of an interceptor,
            // with qualifier @Intercepted, then the type parameter of the injected Bean must be an unbounded wildcard
            if (injectionPointInfo.getRequiredType().name().equals(DotNames.BEAN)
                    && injectionPointInfo.getRequiredQualifier(DotNames.INTERCEPTED) != null
                    && injectionPointInfo.getRequiredType().kind() == Type.Kind.PARAMETERIZED_TYPE) {
                ParameterizedType parameterizedType = injectionPointInfo.getRequiredType().asParameterizedType();
                // there should be exactly one param - wildcard - and it has to be unbound; all else is DefinitionException
                if (parameterizedType.arguments().size() != 1
                        || !(parameterizedType.arguments().get(0).kind() == Type.Kind.WILDCARD_TYPE)
                        || !(parameterizedType.arguments().get(0).asWildcardType().extendsBound().name().equals(DotNames.OBJECT)
                                && parameterizedType.arguments().get(0).asWildcardType().superBound() == null)) {
                    throw new DefinitionException(
                            "Injected @Intercepted Bean<?> has to use unbound wildcard as its type parameter. " +
                                    "Problematic injection point: " + injectionPointInfo.getTargetInfo());
                }
            }
            // the injection point is a field, an initializer method parameter or a bean constructor, with qualifier
            // @Default, then the type parameter of the injected Bean, or Interceptor must be the same as the type
            // declaring the injection point
            if (injectionPointInfo.getRequiredType().name().equals(DotNames.INTERCEPTOR_BEAN)
                    && injectionPointInfo.getRequiredType().kind() == Type.Kind.PARAMETERIZED_TYPE
                    && injectionPointInfo.getRequiredType().asParameterizedType().arguments().size() == 1) {
                Type actualType = injectionPointInfo.getRequiredType().asParameterizedType().arguments().get(0);
                AnnotationTarget ipTarget = injectionPointInfo.getAnnotationTarget();
                DotName expectedType = null;
                if (ipTarget.kind() == Kind.FIELD) {
                    expectedType = ipTarget.asField().declaringClass().name();
                } else if (ipTarget.kind() == Kind.METHOD_PARAMETER) {
                    expectedType = ipTarget.asMethodParameter().method().declaringClass().name();
                }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Change the injection point to use the unbound wildcard: @Inject @Intercepted Bean<?> bean
  2. Remove the @Intercepted qualifier if a typed Bean<T> was intended and legal in that context
  3. Move the injection into an interceptor class (also required — see the @Intercepted placement rule)

Example fix

// before
@Inject @Intercepted Bean<MyService> self;
// after
@Inject @Intercepted Bean<?> self;
Defensive patterns

Strategy: validation

Validate before calling

java.lang.reflect.Type t = MyInterceptor.class.getDeclaredField("bean").getGenericType();
boolean ok = t.getTypeName().equals("jakarta.enterprise.inject.spi.Bean<?>");

Prevention

When it happens

Trigger: Injecting @Intercepted with a concrete type parameter (Bean<MyBean>), a bounded wildcard (Bean<? extends X>), a super-bound wildcard (Bean<? super X>), or a non-parameterized raw Bean type.

Common situations: IDE auto-completing a concrete type parameter; misunderstanding that @Intercepted metadata is typed; mixing up rules for plain Bean<T> vs @Intercepted Bean<?> injections.

Related errors


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