quarkusio/quarkus · error · BlockingOperationNotAllowedException
@Transactional cannot start a JTA transaction within a react
Error message
@Transactional cannot start a JTA transaction within a reactive pipeline. If the annotated method is intended to be blocking, ensure it is executed on a worker thread, for example by annotating it with @Blocking. If the annotated method is intended to be reactive, consider using Hibernate Reactive, which supports @Transactional in a reactive context.
What it means
Quarkus throws BlockingOperationNotAllowedException when @Transactional intercepts a method running inside a reactive pipeline (event-loop / IO thread) where blocking JTA operations are forbidden. Starting or joining a JTA transaction blocks the calling thread, which would stall the event loop, so the BlockingOperationControl check rejects it. The message tells you to either run the method on a worker thread or use a reactive transaction API.
Source
Thrown at extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/interceptor/TransactionalInterceptorBase.java:90
protected TransactionalInterceptorBase(boolean userTransactionAvailable) {
this.userTransactionAvailable = userTransactionAvailable;
}
public Object intercept(InvocationContext ic) throws Exception {
final TransactionManager tm = transactionManager;
final Transaction tx = tm.getTransaction();
boolean previousUserTransactionAvailability = setUserTransactionAvailable(userTransactionAvailable);
try {
return doIntercept(tm, tx, ic);
} finally {
resetUserTransactionAvailability(previousUserTransactionAvailability);
}
}
protected void checkBlockingAllowed() {
if (!BlockingOperationControl.isBlockingAllowed()) {
throw new BlockingOperationNotAllowedException(
"@Transactional cannot start a JTA transaction within a reactive pipeline." +
" If the annotated method is intended to be blocking, ensure it is executed on a worker thread, for example by annotating it with @Blocking."
+
" If the annotated method is intended to be reactive, consider using Hibernate Reactive, which supports @Transactional in a reactive context.");
}
}
protected abstract Object doIntercept(TransactionManager tm, Transaction tx, InvocationContext ic) throws Exception;
/**
* <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 ic invocation context of the interceptorView on GitHub (pinned to e1c734241f)
Solutions
- Annotate the @Transactional method (or its caller) with @Blocking so it runs on a worker thread
- Move the transactional logic behind a blocking bean and call it from a Uni created with emitOn/runSubscriptionOn a worker executor
- Use Hibernate Reactive (quarkus-hibernate-reactive) with reactive transactions instead of JTA for reactive pipelines
- Restructure so event-loop code never directly invokes transactional blocking methods
Example fix
// before
@Transactional
public Order save(Order o) { ... } // called from event loop
// after
@Blocking
@Transactional
public Order save(Order o) { ... } Defensive patterns
Strategy: validation
Validate before calling
boolean safeToRunTransactional = BlockingOperationControl.isBlockingAllowed();
if (!safeToRunTransactional) { /* route to worker thread or use reactive API */ } Try / catch
try { service.save(o); } catch (BlockingOperationNotAllowedException e) {
// re-dispatch on worker thread:
Uni.createFrom().item(() -> service.save(o)).emitOn(executor).await().indefinitely();
} Prevention
- Always pair @Transactional with @Blocking in reactive REST endpoints
- Never call blocking beans directly from event-loop handlers or reactive callbacks
- Prefer Hibernate Reactive for reactive pipelines needing transactions
- Document which service methods are blocking-only
When it happens
Trigger: Calling a @Transactional method from a RESTEasy Reactive (Vert.x event-loop) endpoint or any reactive callback, without @Blocking and without running on a worker thread; @Transactional applied to a method invoked inside Uni/Multi chains.
Common situations: quarkus-rest (reactive) endpoint method is itself @Transactional and executes on the event loop; calling a blocking @Transactional service from an event-loop handler or a reactive messaging callback; forgetting @Blocking (executeOnWorkerThread) when mixing reactive and blocking code.
Related errors
- Blocking gRPC client call made from the event loop. If the c
- Attempting a blocking read on io thread
- You have attempted to perform a blocking operation on a IO t
- @PermissionChecker annotation instance placed on the '%s' re
- Attempting a blocking read on io thread
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/9bcffef7c21467d1.
Report an issue: GitHub.