quarkusio/quarkus · error · ContextNotActiveException
No active transaction on the current thread
Error message
No active transaction on the current thread
What it means
TransactionContext.getState() implements the CDI AlterableContext contract for the transaction context. If no transaction is active on the current thread (isActive() false), it throws ContextNotActiveException("No active transaction on the current thread"). This surfaces when CDI tries to resolve a @TransactionScoped bean outside an active transaction.
Source
Thrown at extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/context/TransactionContext.java:85
}
@Override
public void destroy(Contextual<?> contextual) {
if (!isActive()) {
return;
}
TransactionContextState contextState = (TransactionContextState) transactionSynchronizationRegistry.get()
.getResource(TRANSACTION_CONTEXT_MARKER);
if (contextState == null) {
return;
}
contextState.remove(contextual);
}
@Override
public ContextState getState() {
if (!isActive()) {
throw new ContextNotActiveException("No active transaction on the current thread");
}
ContextState result;
TransactionContextState contextState = (TransactionContextState) transactionSynchronizationRegistry.get()
.getResource(TRANSACTION_CONTEXT_MARKER);
if (contextState == null) {
result = new TransactionContextState(getCurrentTransaction());
} else {
result = contextState;
}
return result;
}
@Override
public Class<? extends Annotation> getScope() {
return TransactionScoped.class;
}
View on GitHub (pinned to e1c734241f)
Solutions
- Add @Transactional (jakarta.transaction.Transactional) to the method or class accessing the bean
- Run the code inside @Transactional activator/quarkus-narayana-jta-managed execution (e.g. via TransactionRunner with REQUIRE_NEW semantics)
- Move state out of @TransactionScoped into @ApplicationScoped if transaction lifetime is not actually needed
Example fix
// before
public Payment payment() { return transactionScopedBean.get(); }
// after
@Transactional
public Payment payment() { return transactionScopedBean.get(); } Defensive patterns
Strategy: try-catch
Validate before calling
if (!CDI.current().select(TransactionContext.class).get().isActive()) { /* enter a transaction or bail out */ } Type guard
boolean txContextActive() { try { return TransactionManager.transactionManager().getStatus() == Status.STATUS_ACTIVE; } catch (Exception e) { return false; } } Try / catch
try { return ctx.getState(); } catch (ContextNotActiveException e) { return null; /* outside transaction */ } Prevention
- Access @TransactionScoped beans only from @Transactional methods
- Avoid transaction-scoped beans for scheduled/async code paths
- Add integration tests that call the bean both with and without a transaction
When it happens
Trigger: Injecting or accessing a @TransactionScoped bean from code running without @Transactional / without an active JTA transaction; calling getContext(TransactionScoped.class).get(...) manually outside a transaction.
Common situations: Forgetting @Transactional on a service method; calling transaction-scoped beans from scheduled tasks, event observers, or background threads without a transaction; programmatic CDI lookups during startup.
Related errors
- The transaction is not active!
- Cannot use the EntityManager/Session because neither a trans
- Cannot use the EntityManager/Session because no transaction
- Cannot use the StatelessSession because neither a transactio
- Cannot use the StatelessSession because no transaction is ac
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/1521d7df40822aa2.
Report an issue: GitHub.