quarkusio/quarkus · error · DefinitionException
Decorator declares an observer method: ${decoratorClass}
Error message
Decorator declares an observer method: ${decoratorClass} What it means
Build-time CDI definition error: a method in the decorator's hierarchy (checked via the annotation store for parameter annotations) carries an @Observes parameter. Decorators cannot host observer methods per the CDI spec, so the deployment is rejected with the decorator class named.
Source
Thrown at independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Decorators.java:171
checkDecoratorFieldsAndMethods(decoratorClass, beanDeployment);
return new DecoratorInfo(decoratorClass, beanDeployment, delegateInjectionPoint,
decoratedTypes, injections, priority);
}
private static void checkDecoratorFieldsAndMethods(ClassInfo decoratorClass, BeanDeployment beanDeployment) {
ClassInfo aClass = decoratorClass;
while (aClass != null) {
for (MethodInfo method : aClass.methods()) {
if (beanDeployment.hasAnnotation(method, DotNames.PRODUCES)) {
throw new DefinitionException("Decorator declares a producer method: " + decoratorClass);
}
// the following 3 checks rely on the annotation store returning parameter annotations for methods
if (beanDeployment.hasAnnotation(method, DotNames.DISPOSES)) {
throw new DefinitionException("Decorator declares a disposer method: " + decoratorClass);
}
if (beanDeployment.hasAnnotation(method, DotNames.OBSERVES)) {
throw new DefinitionException("Decorator declares an observer method: " + decoratorClass);
}
if (beanDeployment.hasAnnotation(method, DotNames.OBSERVES_ASYNC)) {
throw new DefinitionException("Decorator declares an async observer method: " + decoratorClass);
}
}
for (FieldInfo field : aClass.fields()) {
if (beanDeployment.hasAnnotation(field, DotNames.PRODUCES)) {
throw new DefinitionException("Decorator declares a producer field: " + decoratorClass);
}
}
DotName superClass = aClass.superName();
aClass = superClass != null && !superClass.equals(DotNames.OBJECT)
? getClassByName(beanDeployment.getBeanArchiveIndex(), superClass)
: null;
}
}View on GitHub (pinned to e1c734241f)
Solutions
- Remove the @Observes method from the decorator.
- Move observation into a separate @ApplicationScoped observer bean.
- If both behaviors are needed, keep the observer bean and the decorator as distinct components.
- Check inherited methods — the scan covers superclasses.
Example fix
// before
@Decorator
public class D implements Greeter {
void onStart(@Observes StartupEvent e) { }
}
// after
@Decorator
public class D implements Greeter { /* observer moved to a separate bean */ } Defensive patterns
Strategy: validation
Validate before calling
if (decoratorClass.getAnnotation(jakarta.decorator.Decorator.class) != null)
for (Method m : decoratorClass.getMethods())
if (m.isAnnotationPresent(jakarta.enterprise.event.Observes.class))
throw new IllegalStateException("Decorator cannot declare observer: " + m); Prevention
- Place observers in dedicated observer beans, separate from decorators.
- When converting a bean into a decorator, strip all @Observes methods first.
When it happens
Trigger: A @Decorator class has a method with an @Observes-annotated parameter, detected while validating decorator fields and methods.
Common situations: Adding event observation to an existing decorator; class converted from a regular bean (that observed events) into a decorator without removing the observer; copy-paste of observer code.
Related errors
- Decorator declares an async observer method: ${decoratorClas
- Decorator declares a producer method: ${decoratorClass}
- Decorator declares a disposer method: ${decoratorClass}
- Decorator declares a producer field: ${decoratorClass}
- Decorated interface ${decoratedType} not found in the index
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/36471e7cea354942.
Report an issue: GitHub.