{"record":{"id":"e3e4ff7191339625","repo":"flowable/flowable-engine","slug":"delegateclassname-doesn-t-implement-tasklistener","errorCode":null,"errorMessage":"<delegateClassName> doesn't implement TaskListener","messagePattern":"<delegateClassName> doesn't implement TaskListener","errorType":"exception","errorClass":"FlowableIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/helper/ClassDelegate.java","lineNumber":165,"sourceCode":"            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);\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)) {","sourceCodeStart":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/helper/ClassDelegate.java#L147-L183","documentation":"ClassDelegate instantiates the class configured as a task listener and verifies it implements TaskListener before delegating notify() to it. If the object does not implement org.flowable.task.service.delegate.TaskListener, a FlowableIllegalArgumentException naming the offending class is thrown. This guards the engine contract that task listeners expose the notify(DelegateTask) hook.","triggerScenarios":"A user task declares flowable:taskListener with class='<delegateClassName>' and the class does not implement TaskListener; the check fires both from taskListenerInstance() and during notify().","commonSituations":"Pointing a task listener at an ExecutionListener or JavaDelegate class; using the old org.activiti TaskListener import instead of the Flowable one; refactoring removed the interface; wrong fully qualified name in XML.","solutions":["Make the class implement org.flowable.task.service.delegate.TaskListener (notify(DelegateTask)).","Confirm the import is the Flowable TaskListener, not the Activiti or old Flowable 5 one.","Verify the class attribute in the BPMN XML names the correct class.","Rebuild and redeploy the process application."],"exampleFix":"// before\nimport org.activiti.api.task.runtime.events.listener.TaskEventListener;\npublic class MyTaskListener implements TaskEventListener { ... }\n// after\nimport org.flowable.task.service.delegate.TaskListener;\npublic class MyTaskListener implements TaskListener {\n    @Override\n    public void notify(DelegateTask delegateTask) { ... }\n}","handlingStrategy":"validation","validationCode":"Class<?> c = Class.forName(taskListenerClass);\nif (!org.flowable.task.service.delegate.TaskListener.class.isAssignableFrom(c))\n    throw new IllegalStateException(\"Must implement Flowable TaskListener\");","typeGuard":"boolean isValidTaskListener(Object o) { return o instanceof org.flowable.task.service.delegate.TaskListener; }","tryCatchPattern":"try {\n    taskService.complete(taskId);\n} catch (FlowableIllegalArgumentException e) {\n    if (e.getMessage().contains(\"TaskListener\")) { /* fix listener class */ }\n    throw e;\n}","preventionTips":["Import TaskListener from org.flowable.task.service.delegate, not Activiti.","Differentiate plain TaskListener vs TransactionDependentTaskListener attributes.","Test listeners in an embedded engine test before deployment."],"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"}