quarkusio/quarkus · error · SystemException

The transaction is not active!

Error message

The transaction is not active!

What it means

TransactionScopedNotifier.getTransactionId() builds the TransactionId event payload from the current JTA transaction; if TransactionImple.getTransaction() fails (no active transaction on the thread), every exception is converted into jakarta.transaction.SystemException("The transaction is not active!"). It is thrown while firing transaction-scoped observer events, meaning the code ran outside a real transaction.

Source

Thrown at extensions/narayana-jta/runtime/src/main/java/io/quarkus/narayana/jta/runtime/TransactionScopedNotifier.java:50

            beforeDestroyed = Arc.container().beanManager().getEvent()
                    .select(TransactionId.class, BeforeDestroyed.Literal.of(TransactionScoped.class));
        }
        beforeDestroyed.fire(transactionId);
    }

    void destroyed(TransactionId transactionId) {
        if (destroyed == null) {
            destroyed = Arc.container().beanManager().getEvent()
                    .select(TransactionId.class, Destroyed.Literal.of(TransactionScoped.class));
        }
        destroyed.fire(transactionId);
    }

    TransactionId getTransactionId() throws SystemException {
        try {
            return new TransactionId(TransactionImple.getTransaction().toString());
        } catch (Exception e) {
            throw new SystemException("The transaction is not active!");
        }
    }

    // we use this wrapper because if we fire an event with string payload then any "@Observes String payload" would be notified
    public static final class TransactionId {

        private final String value;

        public TransactionId(String value) {
            this.value = value;
        }

        @Override
        public String toString() {
            return value;
        }

        @Override

View on GitHub (pinned to e1c734241f)

Solutions

  1. Annotate the calling method (or a wrapping method) with @Transactional so a transaction is active
  2. Wrap getTransactionId-dependent logic in a check for active transaction status before firing/observing
  3. Catch SystemException and treat it as 'no transaction' if the observer must tolerate transaction-less execution

Example fix

// before
public void doWork() { notifier.getTransactionId(); }
// after
@Transactional
public void doWork() { notifier.getTransactionId(); }
Defensive patterns

Strategy: try-catch

Validate before calling

if (!TransactionManager.transactionManager().getStatus().equals(Status.STATUS_ACTIVE)) { /* skip or start a transaction first */ }

Type guard

boolean hasActiveTransaction() { try { return javax.transaction.Status.STATUS_ACTIVE == com.arjuna.ats.jta.TransactionManager.transactionManager().getStatus(); } catch (Exception e) { return false; } }

Try / catch

try { TransactionId id = getTransactionId(); ... } catch (SystemException e) { log.warn("no active transaction, skipping id"); }

Prevention

When it happens

Trigger: An observer or callback tied to the transaction scope (e.g. @Observes of transaction events via TransactionScopedNotifier) executing when no JTA transaction is active on the current thread — e.g. after commit/rollback completed or code running on a non-transactional thread.

Common situations: @Transactional missing on the entry point so transaction-scoped beans/events run without a transaction; observer logic invoked after the transaction already finished; async threads detached from the transactional context.

Related errors


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