flowable/flowable-engine · error · org.flowable.common.engine.api.FlowableException
SystemException while registering synchronization
Error message
SystemException while registering synchronization
What it means
Flowable wraps the JTA TransactionManager's registerSynchronization() failures into a FlowableException. A SystemException from the underlying transaction manager signals that the transaction service itself failed unexpectedly (internal transaction manager error, wrongly configured TM, or no active transaction support). Flowable rethrows it so the command fails and the engine can roll back cleanly.
Solutions
- Inspect the cause chain (getCause()) for the underlying SystemException message from the JTA transaction manager and fix the TM configuration
- Verify the JTA TransactionManager is properly initialized and accessible before starting commands (e.g. Atomikos/Narayana startup logs)
- Ensure a transaction is actually active when the command runs; do not invoke engine commands outside a JTA transaction in JTA mode
- Check for javax.transaction vs jakarta.transaction duplication on the classpath (Flowable version mismatch with app server)
- Enable debug logging on org.flowable.common.engine.impl.cfg.jta to see the exact failing transaction state
Example fix
// before: engine in JTA mode but no TM registered cfg.setTransactionManager(null); // after BitronixTransactionManager tm = TransactionManagerServices.getTransactionManager(); cfg.setTransactionManager(tm);
Defensive patterns
Strategy: try-catch
Validate before calling
// before executing commands in JTA mode
try {
jakarta.transaction.Transaction tx = transactionManager.getTransaction();
if (tx == null) throw new IllegalStateException("No active JTA transaction");
} catch (SystemException e) {
throw new IllegalStateException("Transaction manager unhealthy: " + e.getMessage(), e);
} Try / catch
try {
flowableCommand.execute(...);
} catch (FlowableException e) {
if (e.getMessage().contains("SystemException while registering synchronization")) {
// inspect e.getCause(); mark transaction rollback-only or fail request
transactionManager.setRollbackOnly();
}
throw e;
} Prevention
- Verify the JTA TransactionManager is started and healthy before running engine commands
- Always run Flowable commands inside an active JTA transaction when using JtaTransactionContext
- Keep javax/jakarta transaction API versions consistent with your Flowable version
- Watch TM logs for startup failures and rollback-only marks
When it happens
Trigger: Calling addTransactionListener to register a TransactionStateSynchronization when the JTA transaction manager is in a broken/failed state; registerSynchronization() on jakarta/javax.transaction.Transaction throws SystemException.
Common situations: Misconfigured JTA transaction manager (e.g. Atomikos/Narayana/Bitronix failing to boot), using the engine outside a proper JTA environment, transaction already marked rollback-only or TM internal failure, classpath mixing javax and jakarta transaction APIs.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- IllegalStateException while registering synchronization
- RollbackException while registering synchronization
- IllegalStateException while registering synchronization
- RollbackException while registering synchronization
- SystemException while getting transaction
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/9d9beb07029f3474.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/cfg/jta/JtaTransactionContext.java:82
return transactionManager.getTransaction();
} catch (SystemException e) {
throw new FlowableException("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) {
throw new FlowableException("IllegalStateException while registering synchronization ", e);
} catch (RollbackException e) {
throw new FlowableException("RollbackException while registering synchronization ", e);
} catch (SystemException e) {
throw new FlowableException("SystemException while registering synchronization ", e);
}
}
public static class TransactionStateSynchronization implements Synchronization {
protected final TransactionListener transactionListener;
protected final TransactionState transactionState;
private final CommandContext commandContext;
public TransactionStateSynchronization(TransactionState transactionState, TransactionListener transactionListener, CommandContext commandContext) {
this.transactionState = transactionState;
this.transactionListener = transactionListener;
this.commandContext = commandContext;
}
@Override
public void beforeCompletion() {
if (TransactionState.COMMITTING == transactionState || TransactionState.ROLLINGBACK == transactionState) {View on GitHub (pinned to d6d39ce1c6)