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

  1. Set the listener's transaction state using TransactionState enum names exactly: TransactionState.COMMITTING.name(), ROLLINGBACK, or ROLLED_BACK
  2. 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
  3. Log/print listener.getOnTransaction() at registration time to confirm the value
  4. 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

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


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)