flowable/flowable-engine · warning
Unrecognised TransactionState
Error message
Unrecognised TransactionState {} What it means
In dispatchTransactionEventListener, the listener's getOnTransaction() string is compared (case-insensitively against COMMITTING/ROLLINGBACK/ROLLED_BACK, but case-SENSITIVELY here) against TransactionState enum names. If it matches none, the transaction listener is never registered and only a warning is logged — the listener silently never fires.
Solutions
- Set the listener's transaction state using TransactionState enum names exactly: TransactionState.COMMITTING.name(), ROLLINGBACK, or ROLLED_BACK
- Check for case mismatches — the final else branch does equalsIgnoreCase on earlier branches but the whole chain must match one of the three states; use the enum constant instead of a hand-written string
- Log/print listener.getOnTransaction() at registration time to confirm the value
- If you need a state not supported (e.g. COMMITTED), register a transaction listener directly on the TransactionContext instead
Example fix
// before
listener.setOnTransaction("COMMITTED"); // never matches -> warn, listener never fires
// after
listener.setOnTransaction(TransactionState.ROLLED_BACK.name()); Defensive patterns
Strategy: validation
Validate before calling
TransactionState[] valid = {TransactionState.COMMITTING, TransactionState.ROLLINGBACK, TransactionState.ROLLED_BACK};
String onTx = listener.getOnTransaction();
boolean ok = onTx != null && Arrays.stream(valid).anyMatch(s -> s.name().equalsIgnoreCase(onTx));
if (!ok) throw new IllegalArgumentException("Unsupported onTransaction: " + onTx); Type guard
boolean isValidTransactionState(String s) {
return s != null && (TransactionState.COMMITTING.name().equalsIgnoreCase(s)
|| TransactionState.ROLLINGBACK.name().equalsIgnoreCase(s)
|| TransactionState.ROLLED_BACK.name().equalsIgnoreCase(s));
} Prevention
- Always derive the value from TransactionState.name() instead of typing strings
- Write a registration-time assertion validating getOnTransaction()
- Avoid overriding getOnTransaction() with custom constants
When it happens
Trigger: A listener registered via addTransactionEventListener or with onTransaction set returns a string that is not exactly COMMITTING, ROLLINGBACK, or ROLLED_BACK (e.g. 'COMMITTED', 'rolled_back', 'committing' with different casing, or a custom value).
Common situations: Typo or wrong casing in a programmatic listener registration; a subclass overrides getOnTransaction() with an unexpected constant; version changes introduce new TransactionState handling the custom string doesn't match.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- Cannot create an event-throwing event-listener, unknown…
- Cannot flush EntityManager, an active transaction is…
- Cannot throw process-instance scoped message, since the…
- Cannot throw process-instance scoped signal, since the…
- Error while flushing EntityManager, illegal state
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/15841a4b78e8b542.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/event/FlowableEventSupport.java:154
if (transactionContext == null) {
return;
}
ExecuteEventListenerTransactionListener transactionListener = new ExecuteEventListenerTransactionListener(listener, event);
if (listener.getOnTransaction().equalsIgnoreCase(TransactionState.COMMITTING.name())) {
transactionContext.addTransactionListener(TransactionState.COMMITTING, transactionListener);
} else if (listener.getOnTransaction().equalsIgnoreCase(TransactionState.COMMITTED.name())) {
transactionContext.addTransactionListener(TransactionState.COMMITTED, transactionListener);
} else if (listener.getOnTransaction().equalsIgnoreCase(TransactionState.ROLLINGBACK.name())) {
transactionContext.addTransactionListener(TransactionState.ROLLINGBACK, transactionListener);
} else if (listener.getOnTransaction().equalsIgnoreCase(TransactionState.ROLLED_BACK.name())) {
transactionContext.addTransactionListener(TransactionState.ROLLED_BACK, transactionListener);
} else {
LOGGER.warn("Unrecognised TransactionState {}", listener.getOnTransaction());
}
}
protected synchronized void addTypedEventListener(FlowableEventListener listener, FlowableEventType type) {
List<FlowableEventListener> listeners = typedListeners.get(type);
if (listeners == null) {
// Add an empty list of listeners for this type
listeners = new CopyOnWriteArrayList<>();
typedListeners.put(type, listeners);
}
if (!listeners.contains(listener)) {
listeners.add(listener);
}
}
}
View on GitHub (pinned to d6d39ce1c6)