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

  1. Ensure the invoked method (or its class) is actually annotated @Transactional and that annotation retention/inheritance is intact.
  2. Check for custom InterceptorBinding/interceptor registrations that intercept the method without @Transactional and fix the binding.
  3. 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

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


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