{"record":{"id":"4bb0499788002ed4","repo":"flowable/flowable-engine","slug":"delegateclassname-doesn-t-implement-transactiond-4bb049","errorCode":null,"errorMessage":"<delegateClassName> doesn't implement TransactionDependentTaskListener","messagePattern":"<delegateClassName> doesn't implement TransactionDependentTaskListener","errorType":"exception","errorClass":"FlowableIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/helper/ClassDelegate.java","lineNumber":174,"sourceCode":"            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);\n        }\n    }\n\n    protected TransactionDependentTaskListener getTransactionDependentTaskListenerInstance() {\n        Object delegateInstance = instantiateDelegate(className, fieldDeclarations);\n        if (delegateInstance instanceof TransactionDependentTaskListener) {\n            return (TransactionDependentTaskListener) delegateInstance;\n        } else {\n            throw new FlowableIllegalArgumentException(delegateInstance.getClass().getName() + \" doesn't implement \" + TransactionDependentTaskListener.class);\n        }\n    }\n\n    // Activity Behavior\n    @Override\n    public void execute(DelegateExecution execution) {\n        if (CommandContextUtil.getProcessEngineConfiguration().isEnableProcessDefinitionInfoCache()) {\n            ObjectNode taskElementProperties = BpmnOverrideContext.getBpmnOverrideElementProperties(serviceTaskId, execution.getProcessDefinitionId());\n            if (taskElementProperties != null && taskElementProperties.has(DynamicBpmnConstants.SERVICE_TASK_CLASS_NAME)) {\n                String overrideClassName = taskElementProperties.get(DynamicBpmnConstants.SERVICE_TASK_CLASS_NAME).asString();\n                if (StringUtils.isNotEmpty(overrideClassName) && !overrideClassName.equals(className)) {\n                    className = overrideClassName;\n                    activityBehaviorInstance = null;\n                }\n            }\n        }\n\n        if (activityBehaviorInstance == null) {","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/helper/ClassDelegate.java#L156-L192","documentation":"ClassDelegate instantiates the class configured as a transaction-dependent task listener and casts it to TransactionDependentTaskListener. If the instance does not implement that interface, a FlowableIllegalArgumentException naming the class and expected interface is thrown. Flowable needs this interface to invoke listeners during the transaction commit/rollback phases of a task.","triggerScenarios":"A user task declares flowable:transactionDependentTaskListener class='<delegateClassName>' and the class does not implement org.flowable.engine.delegate.TransactionDependentTaskListener.","commonSituations":"Reusing a plain TaskListener class under the transactionDependent variant; refactoring dropped the interface; wrong class name in the BPMN XML; stale deployed jar missing the implementation.","solutions":["Make the configured class implement TransactionDependentTaskListener (getListenerEvents + notify).","Check the XML class attribute matches the intended fully qualified class.","Redeploy so the deployed artifact contains the implementation.","Use a regular flowable:taskListener if transaction-phase notification is not required."],"exampleFix":"// before\npublic class MyListener implements TaskListener { ... }\n<!-- flowable:transactionDependentTaskListener class=\"com.acme.MyListener\" -->\n// after\npublic class MyListener implements TransactionDependentTaskListener {\n    @Override public Set<String> getListenerEvents() { return Collections.singleton(EVENTNAME_COMMITTED); }\n    @Override public void notify(TransactionDependentTaskListenerExecution execution, List<TaskInfo> tasks) { ... }\n}","handlingStrategy":"validation","validationCode":"Class<?> c = Class.forName(listenerClass);\nif (!TransactionDependentTaskListener.class.isAssignableFrom(c))\n    throw new IllegalStateException(\"Must implement TransactionDependentTaskListener\");","typeGuard":"boolean isValid(Object o) { return o instanceof TransactionDependentTaskListener; }","tryCatchPattern":"try {\n    taskService.complete(taskId);\n} catch (FlowableIllegalArgumentException e) {\n    if (e.getMessage().contains(\"TransactionDependentTaskListener\")) { /* fix class */ }\n    throw e;\n}","preventionTips":["Use transactionDependentTaskListener only with the matching interface.","Keep listener events set (getListenerEvents) implemented alongside notify.","Validate all listener classes at deployment time."],"tags":["flowable","delegate","task-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"}