flowable/flowable-engine · error · ActivitiException

SystemException while marking transaction rollback only

Error message

SystemException while marking transaction rollback only

What it means

JtaTransactionContext.rollback() wraps javax.transaction.SystemException from Transaction.setRollbackOnly() in this ActivitiException. SystemException indicates the transaction manager itself failed (internal error, resource failure) while marking the transaction for rollback.

Solutions

  1. Check the application server / transaction manager logs at the correlated timestamp for the root SystemException.
  2. Verify XA datasource and recovery configuration in the app server.
  3. Confirm the TransactionManager lookup (e.g. JBossStandAloneJtaTransactionManager vs container lookup) is correct for your environment.
  4. Retry the operation once the transaction service is healthy; if persistent, restart the transaction service or server.
Defensive patterns

Strategy: retry

Validate before calling

// health-check the transaction service before commands
UserTransaction ut = ...; ut.getStatus(); // throws early if service is broken

Try / catch

try { engineCommand(); } catch (ActivitiException e) { if (e.getCause() instanceof SystemException) { alertOps("JTA transaction manager failure"); } else { throw e; } }

Prevention

When it happens

Trigger: Calling rollback() when the underlying JTA TransactionManager or its resources are broken — e.g. transaction manager service unavailable, recoverable internal error reported by the JTA provider.

Common situations: App-server transaction service failures or restarts mid-request; misconfigured XA datasource; transaction timeout leaving the manager in a broken state during engine command teardown.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/187406e777d161c3. Report an issue: GitHub.

Appendix: source

Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/cfg/jta/JtaTransactionContext.java:58

    @Override
    public void commit() {
        // managed transaction, ignore
    }

    @Override
    public void rollback() {
        // managed transaction, mark rollback-only if not done so already.
        try {
            Transaction transaction = getTransaction();
            int status = transaction.getStatus();
            if (status != Status.STATUS_NO_TRANSACTION && status != Status.STATUS_ROLLEDBACK) {
                transaction.setRollbackOnly();
            }
        } catch (IllegalStateException e) {
            throw new ActivitiException("Unexpected IllegalStateException while marking transaction rollback only", e);
        } catch (SystemException e) {
            throw new ActivitiException("SystemException while marking transaction rollback only", e);
        }
    }

    protected Transaction getTransaction() {
        try {
            return transactionManager.getTransaction();
        } catch (SystemException e) {
            throw new ActivitiException("SystemException while getting transaction ", e);
        }
    }

    @Override
    public void addTransactionListener(TransactionState transactionState, final TransactionListener transactionListener) {
        Transaction transaction = getTransaction();
        CommandContext commandContext = Context.getCommandContext();
        try {
            transaction.registerSynchronization(new TransactionStateSynchronization(transactionState, transactionListener, commandContext));
        } catch (IllegalStateException e) {

View on GitHub (pinned to d6d39ce1c6)