quarkusio/quarkus · error · RuntimeException
Cannot find a @Transactional annotation
Error message
Cannot find a @Transactional annotation
What it means
The interceptor searches the current interceptor bindings for a @Transactional annotation; if none is present the annotation lookup cannot proceed and it throws RuntimeException("Cannot find a @Transactional annotation"). This indicates the interceptor was invoked without the expected binding, usually due to interception misconfiguration.
Source
Thrown at extensions/reactive-transactions/runtime/src/main/java/io/quarkus/reactive/transaction/runtime/TransactionalInterceptorBase.java:336
/**
* <p>
* Looking for the {@link Transactional} annotation first on the method,
* second on the class.
* <p>
* Method handles CDI types to cover cases where extensions are used. In
* case of EE container uses reflection.
*
* @param context invocation context of the interceptor
* @return instance of {@link Transactional} annotation or null
*/
private Transactional getTransactionalAnnotation(InvocationContext context) {
Set<Annotation> bindings = InterceptorBindings.getInterceptorBindings(context);
for (Annotation binding : bindings) {
if (binding.annotationType() == Transactional.class) {
return (Transactional) binding;
}
}
throw new RuntimeException("Cannot find a @Transactional annotation");
}
}
View on GitHub (pinned to e1c734241f)
Solutions
- Ensure the invoked method (or its class) is actually annotated @Transactional and that annotation retention/inheritance is intact.
- Check for custom InterceptorBinding/interceptor registrations that intercept the method without @Transactional and fix the binding.
- Rebuild and clear incremental build state; if using interception factories, make sure @Transactional is included in the bindings passed.
Defensive patterns
Strategy: validation
Validate before calling
// before invoking through a custom interception path
Transactional tx = method.getAnnotation(Transactional.class);
if (tx == null)
throw new IllegalStateException("Interceptor requires @Transactional on " + method); Try / catch
try {
return service.op();
} catch (RuntimeException e) {
if ("Cannot find a @Transactional annotation".equals(e.getMessage()))
log.error("Interception bindings lost; check CDI wiring for the target bean");
throw e;
} Prevention
- Don't strip/override @Transactional via custom interceptor bindings
- Avoid invoking interceptors manually; rely on CDI-managed beans
- Verify bindings when using InterceptionFactory
- Rebuild cleanly after upgrading Quarkus to refresh ArC metadata
When it happens
Trigger: Invoking the reactive transactional interceptor on a bean/method whose effective interceptor bindings lack @Transactional (e.g. binding metadata removed/overridden, interceptor bound globally but annotation lost via inheritance or custom interception factory).
Common situations: Custom interceptor binding wiring that strips @Transactional; ArC/CDI interception edge cases with generics or default methods; incorrect interceptor priority configuration shadowing the annotation.
Related errors
- Interceptor class ${interceptorClass} is not a CDI bean. Onl
- While using @Transactional we need a DatabaseActions Strateg
- Multiple @AroundInvoke interceptor methods declared on class
- Multiple @AroundConstruct interceptor methods declared on cl
- Multiple @PostConstruct interceptor methods declared on clas
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/9c3ad824de221109.
Report an issue: GitHub.