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

  1. Remove the @Observes method from the decorator.
  2. Move observation into a separate @ApplicationScoped observer bean.
  3. If both behaviors are needed, keep the observer bean and the decorator as distinct components.
  4. 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

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


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