{"record":{"id":"f7177032144c25c6","repo":"flowable/flowable-engine","slug":"exception-while-executing-event-listener-which-wa-f71770","errorCode":null,"errorMessage":"Exception while executing event-listener, which was ignored","messagePattern":"Exception while executing event-listener, which was ignored","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/event/FlowableEventSupport.java","lineNumber":129,"sourceCode":"\n    protected void dispatchEvent(FlowableEvent event, FlowableEventListener listener) {\n        if (listener.isFireOnTransactionLifecycleEvent()) {\n            dispatchTransactionEventListener(event, listener);\n        } else {\n            dispatchNormalEventListener(event, listener);\n        }\n    }\n\n    protected void dispatchNormalEventListener(FlowableEvent event, FlowableEventListener listener) {\n        try {\n            listener.onEvent(event);\n        } catch (Throwable t) {\n            if (listener.isFailOnException()) {\n                throw t;\n            } else {\n                // Ignore the exception and continue notifying remaining listeners. The listener\n                // explicitly states that the exception should not bubble up\n                LOGGER.warn(\"Exception while executing event-listener, which was ignored\", t);\n            }\n        }\n    }\n\n    protected void dispatchTransactionEventListener(FlowableEvent event, FlowableEventListener listener) {\n        TransactionContext transactionContext = Context.getTransactionContext();\n        if (transactionContext == null) {\n            return;\n        }\n        \n        ExecuteEventListenerTransactionListener transactionListener = new ExecuteEventListenerTransactionListener(listener, event); \n        if (listener.getOnTransaction().equalsIgnoreCase(TransactionState.COMMITTING.name())) {\n            transactionContext.addTransactionListener(TransactionState.COMMITTING, transactionListener);\n            \n        } else if (listener.getOnTransaction().equalsIgnoreCase(TransactionState.COMMITTED.name())) {\n            transactionContext.addTransactionListener(TransactionState.COMMITTED, transactionListener);\n            \n        } else if (listener.getOnTransaction().equalsIgnoreCase(TransactionState.ROLLINGBACK.name())) {","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/event/FlowableEventSupport.java#L111-L147","documentation":"FlowableEventSupport dispatches engine events to registered FlowableEventListener instances. If a listener throws a Throwable and its isFailOnException() returns false, the exception is deliberately swallowed and only logged as a warning, so the remaining listeners still get notified. This means an exception thrown inside your listener implementation will NOT propagate to the caller or roll back the transaction unless the listener opts in.","triggerScenarios":"Any FlowableEventListener whose isFailOnException() returns false (the default for most base listener implementations) throws a Throwable from notify(FlowableEvent) while dispatchEvent iterates the listener list.","commonSituations":"A custom global event listener hits a NullPointerException or DB error in its handler code; a listener calls a flaky external service; developers are confused why their listener bug 'disappears' and only shows up as a WARN in logs.","solutions":["Inspect the WARN stack trace in logs to find the throwing listener and fix the bug in its notify() implementation","If the exception must abort the operation, override isFailOnException() on your listener to return true so the Throwable is rethrown","Make the listener body defensive: wrap risky work (remote calls, parsing) in its own try-catch or move it to async processing","Verify the correct listener is registered for the event type via addEventListeners/addTypedEventListener; a mis-registered listener may receive events it cannot handle"],"exampleFix":"// before\npublic class MyListener implements FlowableEventListener {\n    public void notify(FlowableEvent event) {\n        process(event); // throws NPE -> swallowed with WARN\n    }\n}\n// after\npublic class MyListener implements FlowableEventListener {\n    public void notify(FlowableEvent event) {\n        process(event);\n    }\n    @Override\n    public boolean isFailOnException() {\n        return true; // rethrow so engine/transaction sees the failure\n    }\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    listener.notify(event);\n} catch (Throwable t) {\n    if (listener.isFailOnException()) {\n        throw t;\n    }\n    log.warn(\"listener failed; event {}\", event.getType(), t);\n}","preventionTips":["Keep listener notify() bodies small and wrap risky side effects in their own error handling","Override isFailOnException() to return true when the failure must abort the transaction","Monitor WARN logs from FlowableEventSupport in production to catch silent listener bugs","Unit-test listeners against all event types they are registered for"],"tags":["flowable","event-listener","logging","exception-swallowing"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}