{"record":{"id":"8003321c0851ef6a","repo":"flowable/flowable-engine","slug":"delegateclassname-doesn-t-implement-transactiond","errorCode":null,"errorMessage":"<delegateClassName> doesn't implement TransactionDependentExecutionListener","messagePattern":"<delegateClassName> doesn't implement TransactionDependentExecutionListener","errorType":"exception","errorClass":"FlowableIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/helper/ClassDelegate.java","lineNumber":147,"sourceCode":"        CommandContextUtil.getProcessEngineConfiguration().getDelegateInterceptor().handleInvocation(new TaskListenerInvocation(taskListenerInstance, delegateTask));\n    }\n\n    @Override\n    public void notify(String processInstanceId, String executionId, Task task, Map<String, Object> executionVariables, Map<String, Object> customPropertiesMap) {\n        TransactionDependentTaskListener transactionDependentTaskListenerInstance = getTransactionDependentTaskListenerInstance();\n        transactionDependentTaskListenerInstance.notify(processInstanceId, executionId, task, executionVariables, customPropertiesMap);\n    }\n\n    protected ExecutionListener getExecutionListenerInstance() {\n        return new DelegateExecutionListener(instantiateDelegate(className, fieldDeclarations));\n    }\n\n    protected TransactionDependentExecutionListener getTransactionDependentExecutionListenerInstance() {\n        Object delegateInstance = instantiateDelegate(className, fieldDeclarations);\n        if (delegateInstance instanceof TransactionDependentExecutionListener) {\n            return (TransactionDependentExecutionListener) delegateInstance;\n        } else {\n            throw new FlowableIllegalArgumentException(delegateInstance.getClass().getName() + \" doesn't implement \" + TransactionDependentExecutionListener.class);\n        }\n    }\n\n    protected CustomPropertiesResolver getCustomPropertiesResolverInstance() {\n        Object delegateInstance = instantiateDelegate(className, fieldDeclarations);\n        if (delegateInstance instanceof CustomPropertiesResolver) {\n            return (CustomPropertiesResolver) delegateInstance;\n        } else {\n            throw new FlowableIllegalArgumentException(delegateInstance.getClass().getName() + \" doesn't implement \" + CustomPropertiesResolver.class);\n        }\n    }\n\n    protected TaskListener getTaskListenerInstance() {\n        Object delegateInstance = instantiateDelegate(className, fieldDeclarations);\n        if (delegateInstance instanceof TaskListener) {\n            return (TaskListener) delegateInstance;\n        } else {\n            throw new FlowableIllegalArgumentException(delegateInstance.getClass().getName() + \" doesn't implement \" + TaskListener.class);","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/helper/ClassDelegate.java#L129-L165","documentation":"Flowable's ClassDelegate instantiates the class configured for a transaction-dependent execution listener and checks that it implements TransactionDependentExecutionListener. If the instantiated object does not implement that interface, a FlowableIllegalArgumentException is thrown naming the class and the missing interface. The library enforces this contract because it must invoke the listener's transaction-aware notification methods during commit/rollback phases.","triggerScenarios":"A BPMN element (e.g. service task or user task) is configured with flowable:transactionDependentExecutionListener class='<delegateClassName>', and the referenced class (or a field-declaration instantiation of it) does not implement org.flowable.engine.delegate.TransactionDependentExecutionListener.","commonSituations":"Copy-pasting an ordinary ExecutionListener/JavaDelegate class into a transactionDependentExecutionListener attribute; renaming or refactoring the class so it no longer implements the interface; pointing the XML at the wrong class name; classpath collisions loading a stale version of the class.","solutions":["Make the configured class implement org.flowable.engine.delegate.TransactionDependentExecutionListener (notify method taking TransactionDependentExecutionListenerExecution).","Verify the class name in the BPMN XML matches the fully qualified name of the intended implementation.","Rebuild/redeploy so the deployed classpath contains the compiled implementation of the interface.","If you meant a plain listener, move the class to the flowable:executionListener attribute instead."],"exampleFix":"// before\npublic class MyListener implements ExecutionListener { ... }\n<!-- flowable:transactionDependentExecutionListener class=\"com.acme.MyListener\" -->\n// after\npublic class MyListener implements TransactionDependentExecutionListener {\n    @Override\n    public void notify(TransactionDependentExecutionListenerExecution execution) { ... }\n}","handlingStrategy":"validation","validationCode":"Class<?> c = Class.forName(\"com.acme.MyListener\");\nif (!TransactionDependentExecutionListener.class.isAssignableFrom(c))\n    throw new IllegalStateException(\"Class must implement TransactionDependentExecutionListener\");","typeGuard":"boolean isValidListener(Object o) { return o instanceof TransactionDependentExecutionListener; }","tryCatchPattern":"try {\n    runtimeService.startProcessInstanceByKey(\"key\");\n} catch (FlowableIllegalArgumentException e) {\n    if (e.getMessage().contains(\"TransactionDependentExecutionListener\")) { /* fix deployment/class */ }\n    throw e;\n}","preventionTips":["Always implement the exact interface named in the error message with the Flowable package prefix.","Unit-test delegate instantiation before deploying the process.","Keep class attributes in BPMN as constants shared with the class definitions.","Run a smoke deployment test in CI that resolves all delegates."],"tags":["flowable","delegate","listener","type-mismatch"],"backgroundTag":"type-mismatch","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"}