quarkusio/quarkus · error · DefinitionException

Decorator declares an async observer method: ${decoratorClas

Error message

Decorator declares an async observer method: ${decoratorClass}

What it means

Build-time CDI definition error: a method in the decorator's class hierarchy has an @ObservesAsync parameter. Async observers are not allowed on decorators; ArC rejects the bean deployment naming the offending decorator class.

Source

Thrown at independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/Decorators.java:174

                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 @ObservesAsync method from the decorator.
  2. Move async observation to a dedicated observer bean.
  3. Keep the decorator focused on decorating the target interface only.
  4. Verify superclasses, as the validation includes inherited methods.

Example fix

// before
@Decorator
public class D implements Greeter {
    void onTick(@ObservesAsync TickEvent e) { }
}

// after
@Decorator
public class D implements Greeter { /* observer moved out */ }
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.ObservesAsync.class))
            throw new IllegalStateException("Decorator cannot declare async observer: " + m);

Prevention

When it happens

Trigger: A @Decorator class declares a method with an @ObservesAsync-annotated parameter, found by checkDecoratorFieldsAndMethods.

Common situations: Reactive refactor adding async observers onto a decorator; leftover @ObservesAsync after a class became a decorator; copying an async observer into the decorator.

Related errors


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