quarkusio/quarkus · error · DefinitionException
A decorator must be @Dependent but ${decoratorClass} declare
Error message
A decorator must be @Dependent but ${decoratorClass} declares ${scopeAnnotation.getDotName()} What it means
Per CDI, a decorator must be a @Dependent-scoped bean. During Decorators.createDecorator, Arc scans the decorator class annotations; if it finds a scope annotation other than @Dependent (e.g. @ApplicationScoped), it throws this DefinitionException.
Source
Thrown at independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Decorators.java:67
}
}
if (delegateInjectionPoints.isEmpty()) {
throw new DefinitionException("The decorator " + decoratorClass + " has no @Delegate injection point");
} else if (delegateInjectionPoints.size() > 1) {
throw new DefinitionException(
"The decorator " + decoratorClass + " has multiple @Delegate injection points: " + delegateInjectionPoints);
}
InjectionPointInfo delegateInjectionPoint = delegateInjectionPoints.get(0);
Integer priority = null;
for (AnnotationInstance annotation : beanDeployment.getAnnotations(decoratorClass)) {
if (annotation.name().equals(DotNames.PRIORITY)) {
priority = annotation.value().asInt();
}
ScopeInfo scopeAnnotation = beanDeployment.getScope(annotation.name());
if (scopeAnnotation != null && !BuiltinScope.DEPENDENT.is(scopeAnnotation)) {
throw new DefinitionException(
"A decorator must be @Dependent but " + decoratorClass + " declares " + scopeAnnotation.getDotName());
}
}
// The set includes all bean types which are Java interfaces, except for java.io.Serializable
TypeClosure typeClosure = Types.getClassBeanTypeClosure(decoratorClass, beanDeployment);
Set<Type> types = typeClosure.types();
Set<Type> decoratedTypes = new HashSet<>();
for (Type type : types) {
if (type.name().equals(DotNames.SERIALIZABLE)) {
continue;
}
ClassInfo clazz = beanDeployment.getBeanArchiveIndex().getClassByName(type.name());
if (Modifier.isInterface(clazz.flags())) {
decoratedTypes.add(type);
}
}
if (decoratedTypes.isEmpty()) {View on GitHub (pinned to e1c734241f)
Solutions
- Remove the scope annotation so the decorator defaults to @Dependent, or explicitly annotate @Dependent
- If scoped behavior is required, move state into the decorated bean or a separate bean the decorator delegates through
Example fix
// before
@Decorator
@ApplicationScoped
public class MyDecorator implements MyIface { ... }
// after
@Decorator
@Dependent
public class MyDecorator implements MyIface { ... } Defensive patterns
Strategy: validation
Validate before calling
static void requireDependentScope(Class<?> decorator) {
for (var a : decorator.getAnnotations()) {
if (a.annotationType().isAnnotationPresent(jakarta.enterprise.context.NormalScope.class)
|| a.annotationType().isAnnotationPresent(jakarta.inject.Scope.class)) {
if (a.annotationType() != jakarta.enterprise.context.Dependent.class)
throw new IllegalStateException("Decorator must be @Dependent: " + a);
}
}
} Type guard
static boolean isDependentScoped(Class<?> decorator) {
return decorator.isAnnotationPresent(jakarta.enterprise.context.Dependent.class)
|| java.util.Arrays.stream(decorator.getAnnotations()).noneMatch(a ->
a.annotationType().isAnnotationPresent(jakarta.enterprise.context.NormalScope.class)
|| a.annotationType().isAnnotationPresent(jakarta.inject.Scope.class));
} Prevention
- Never add scope annotations to @Decorator classes
- Review IDE quick-fixes that suggest adding @ApplicationScoped to new classes
When it happens
Trigger: Annotating a @Decorator class with @ApplicationScoped, @RequestScoped, @Singleton or any other normal/psuedo scope instead of @Dependent.
Common situations: IDE auto-adding a scope annotation; copying a regular bean class and adding @Decorator without removing @ApplicationScoped; misunderstanding that decorators inherit scope.
Related errors
- Unable to construct type for ${decorator}: ${e.getMessage()}
- Decorated type not found in the bean archive index: ${decora
- The decorator ${decoratorClass} has no @Delegate injection p
- The decorator ${decoratorClass} has multiple @Delegate injec
- Interceptor declares scope other than @Dependent:
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/ef1ac65fcaf391fa.
Report an issue: GitHub.