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

  1. Add @Transactional (jakarta.transaction.Transactional) to the method or class accessing the bean
  2. Run the code inside @Transactional activator/quarkus-narayana-jta-managed execution (e.g. via TransactionRunner with REQUIRE_NEW semantics)
  3. 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

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


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