quarkusio/quarkus · error · QuarkusTransactionException

Transaction already active

Error message

Transaction already active

What it means

RequestScopedTransaction.begin starts the request-scoped user transaction and throws QuarkusTransactionException('Transaction already active') if the underlying UserTransaction's status is not STATUS_NO_TRANSACTION, i.e. a transaction is already in progress on the thread. This guards the commit-on-request-scope-end contract against double begin.

Source

Thrown at extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/RequestScopedTransaction.java:57

            TransactionManager transactionManager, TransactionManagerConfiguration transactionManagerConfiguration) {
        this.userTransaction = userTransaction;
        this.transactionManager = transactionManager;
        this.transactionManagerConfiguration = transactionManagerConfiguration;
    }

    public RequestScopedTransaction() {
        //for proxiability
        this.userTransaction = null;
        this.transactionManagerConfiguration = null;
        this.transactionManager = null;
    }

    void begin(BeginOptions options) {
        int timeout = options != null ? options.timeout : 0;
        boolean commitOnRequestScopeEnd = options != null && options.commitOnRequestScopeEnd;
        try {
            if (userTransaction.getStatus() != Status.STATUS_NO_TRANSACTION) {
                throw new QuarkusTransactionException("Transaction already active");

            }
            this.autoCommit = commitOnRequestScopeEnd;
            if (timeout > 0) {
                userTransaction.setTransactionTimeout(timeout);
            }
            userTransaction.begin();
            createdTransaction = transactionManager.getTransaction();
        } catch (NotSupportedException | SystemException e) {
            throw new QuarkusTransactionException(e);
        } finally {
            if (timeout > 0) {
                try {
                    userTransaction.setTransactionTimeout(
                            (int) transactionManagerConfiguration.defaultTransactionTimeout().toSeconds());
                } catch (SystemException e) {
                    throw new QuarkusTransactionException(e);
                }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Do not call QuarkusTransaction.begin when a transaction is already active — check QuarkusTransaction.isActive() first
  2. Ensure previous transactions are committed/rolled back (look for missing commit/rollback in error paths)
  3. Avoid mixing manual UserTransaction usage with request-scoped transaction management
  4. If a stale transaction leaks from earlier work, roll it back before beginning a new one

Example fix

// before
QuarkusTransaction.begin(); // may throw if already active
// after
if (!QuarkusTransaction.isActive()) {
    QuarkusTransaction.begin();
}
Defensive patterns

Strategy: try-catch

Validate before calling

try {
    int status = userTransaction.getStatus();
    if (status != Status.STATUS_NO_TRANSACTION) {
        throw new IllegalStateException("Cannot begin: transaction status=" + status);
    }
} catch (SystemException e) { /* handle */ }

Try / catch

try {
    QuarkusTransaction.begin();
} catch (QuarkusTransactionException e) {
    if (e.getMessage().contains("Transaction already active")) {
        QuarkusTransaction.rollback(); // or join existing tx instead
        QuarkusTransaction.begin();
    } else throw e;
}

Prevention

When it happens

Trigger: The request-scoped transaction bean's begin() is invoked twice in one request scope, or an external transaction (manual UserTransaction.begin, Narayana timeout recovery, or another component) was already started before the request-scoped transaction initializes.

Common situations: Mixing programmatic QuarkusTransaction.begin with the automatic request-scoped transaction management; a leaked/unclosed transaction from an earlier request handled by the same worker thread; nested service calls each triggering begin.

Related errors


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