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
- Keep one @PreDestroy method per class and delegate to other cleanup methods as plain (unannotated) helpers.
- Remove the @PreDestroy annotation from the redundant method.
- 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
- One @PreDestroy per class; delegate to unannotated cleanup helpers
- When merging interceptors, consolidate cleanup logic immediately
- Include superclass methods in any annotation audit
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
- Multiple @PostConstruct interceptor methods declared on clas
- Multiple @AroundInvoke interceptor methods declared on class
- Multiple @AroundConstruct interceptor methods declared on cl
- An interceptor field cannot be marked @Produces -
- interceptor method validation message (dynamically built: mu
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/b959e29f1224f26f.
Report an issue: GitHub.