quarkusio/quarkus · error · DefinitionException

Multiple @PreDestroy interceptor methods declared on class:

Error message

Multiple @PreDestroy interceptor methods declared on class: 

What it means

ArC throws this DefinitionException when an interceptor class (or any single class in its hierarchy) declares more than one non-static method annotated with @PreDestroy. The CDI specification allows at most one @PreDestroy lifecycle callback interceptor method per interceptor class. This is detected at build time during bean discovery and aborts deployment.

Source

Thrown at independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/InterceptorInfo.java:142

                            InterceptorPlacement.INTERCEPTOR_CLASS);
                    if (++aroundConstructsFound > 1) {
                        throw new DefinitionException(
                                "Multiple @AroundConstruct interceptor methods declared on class: " + aClass);
                    }
                }
                if (store.hasAnnotation(method, DotNames.POST_CONSTRUCT)) {
                    addInterceptorMethod(allMethods, postConstructs, method, InterceptionType.POST_CONSTRUCT,
                            InterceptorPlacement.INTERCEPTOR_CLASS);
                    if (++postConstructsFound > 1) {
                        throw new DefinitionException(
                                "Multiple @PostConstruct interceptor methods declared on class: " + aClass);
                    }
                }
                if (store.hasAnnotation(method, DotNames.PRE_DESTROY)) {
                    addInterceptorMethod(allMethods, preDestroys, method, InterceptionType.PRE_DESTROY,
                            InterceptorPlacement.INTERCEPTOR_CLASS);
                    if (++preDestroysFound > 1) {
                        throw new DefinitionException(
                                "Multiple @PreDestroy interceptor methods declared on class: " + aClass);
                    }
                }
                allMethods.add(method);
            }

            for (FieldInfo field : aClass.fields()) {
                if (store.hasAnnotation(field, DotNames.PRODUCES)) {
                    // according to spec, finding @Produces on a field is a DefinitionException
                    throw new DefinitionException(
                            "An interceptor field cannot be marked @Produces - " + field + " in class: " + aClass);
                }
            }

            DotName superTypeName = aClass.superName();
            aClass = superTypeName == null || DotNames.OBJECT.equals(superTypeName) ? null
                    : getClassByName(beanDeployment.getBeanArchiveIndex(), superTypeName);
        }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Keep one @PreDestroy method per class and delegate to other cleanup methods as plain (unannotated) helpers.
  2. Remove the @PreDestroy annotation from the redundant method.
  3. Split the interceptor into separate classes if the cleanup concerns are independent.

Example fix

// before
class MyInterceptor {
    @PreDestroy void close1(InvocationContext ctx) throws Exception { ctx.proceed(); }
    @PreDestroy void close2(InvocationContext ctx) throws Exception { ctx.proceed(); }
}
// after
class MyInterceptor {
    @PreDestroy void close(InvocationContext ctx) throws Exception { cleanup(); ctx.proceed(); }
    void cleanup() { /* ... */ }
}
Defensive patterns

Strategy: validation

Validate before calling

long n = java.util.Arrays.stream(MyInterceptor.class.getDeclaredMethods())
    .filter(m -> m.isAnnotationPresent(jakarta.annotation.PreDestroy.class))
    .count();
if (n > 1) throw new IllegalStateException("Only one @PreDestroy allowed per interceptor class");

Prevention

When it happens

Trigger: Two or more non-static @PreDestroy-annotated methods in the same interceptor class. One @PreDestroy per class is allowed across the hierarchy (superclass and subclass each may have one).

Common situations: Merging cleanup logic from two interceptors into one class; copy-paste when subclassing an interceptor; adding a second cleanup method without removing the old annotation.

Related errors


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