quarkusio/quarkus · error · TransactionRequiredException

Transaction is not active, consider adding @Transactional to

Error message

Transaction is not active, consider adding @Transactional to your method to automatically activate one.

What it means

persist() in TransactionScopedSession first acquires a session; if the session was obtained only via the request-scoped fallback (emr.allowModification == false, meaning no transaction is active), Quarkus rejects the write with a JPA TransactionRequiredException. This mirrors the JPA spec: persist is a transactional operation and must run inside a transaction.

Source

Thrown at extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/session/TransactionScopedSession.java:168

                case Status.STATUS_COMMITTING:
                case Status.STATUS_MARKED_ROLLBACK:
                case Status.STATUS_PREPARED:
                case Status.STATUS_PREPARING:
                    return true;
                default:
                    return false;
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void persist(Object entity) {
        checkBlocking();
        try (SessionResult emr = acquireSession()) {
            if (!emr.allowModification) {
                throw new TransactionRequiredException(TRANSACTION_IS_NOT_ACTIVE);
            }
            emr.session.persist(entity);
        }
    }

    @Override
    public <T> T merge(T entity) {
        checkBlocking();
        try (SessionResult emr = acquireSession()) {
            if (!emr.allowModification) {
                throw new TransactionRequiredException(TRANSACTION_IS_NOT_ACTIVE);
            }
            return emr.session.merge(entity);
        }
    }

    @Override
    public void remove(Object entity) {

View on GitHub (pinned to e1c734241f)

Solutions

  1. Add @Transactional to the method (or a service layer method) that calls persist so a transaction is active and allowModification is true.
  2. Alternatively begin a transaction programmatically (UserTransaction.begin()/commit()) around the persist call.
  3. Keep write operations out of request-scoped (read-only) code paths; route writes through a transactional bean.
  4. If you expected this to fail earlier with ContextNotActiveException, note that enabling quarkus.hibernate-orm.request-scoped.enabled changes the failure mode to TransactionRequiredException on writes.

Example fix

// before
@ApplicationScoped
public class UserService {
    @Inject EntityManager em;
    public void register(User u) {
        em.persist(u); // TransactionRequiredException
    }
}

// after
@ApplicationScoped
public class UserService {
    @Inject EntityManager em;
    @Transactional
    public void register(User u) {
        em.persist(u);
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

boolean canPersistNow() {
    return quarkusTx() != null && quarkusTx().isActive();
    // or check request-scoped path allowModification indirectly:
    // if request-scoped.enabled=true and no @Transactional, persist will throw
}

Try / catch

try {
    em.persist(entity);
} catch (TransactionRequiredException e) {
    // no active transaction: re-run inside a transactional bean
    txUserService.persist(entity);
}

Prevention

When it happens

Trigger: Calling em.persist(entity) on the injected (transaction-scoped) EntityManager while quarkus.hibernate-orm.request-scoped.enabled=true and no @Transactional is active: a session is created in the request context, but since allowModification is false, persist throws TransactionRequiredException instead of silently doing nothing.

Common situations: Read endpoints that were extended to write without adding @Transactional; enabling request-scoped.enabled for read convenience and then assuming writes work; REST GET/POST handlers that call the EM directly; tests that exercise persist without a transaction.

Related errors


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