{"record":{"id":"9e0843a9f8e10ec9","repo":"flowable/flowable-engine","slug":"s-doesn-t-implement-s","errorCode":null,"errorMessage":"%s doesn't implement %s","messagePattern":"(.+?) doesn't implement (.+?)","errorType":"validation","errorClass":"ActivitiIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/helper/ClassDelegate.java","lineNumber":134,"sourceCode":"    public void notify(DelegateTask delegateTask) {\n        if (taskListenerInstance == null) {\n            taskListenerInstance = getTaskListenerInstance();\n        }\n        try {\n            Context.getProcessEngineConfiguration()\n                    .getDelegateInterceptor()\n                    .handleInvocation(new TaskListenerInvocation(taskListenerInstance, delegateTask));\n        } catch (Exception e) {\n            throw new ActivitiException(\"Exception while invoking TaskListener: \" + e.getMessage(), e);\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 ActivitiIllegalArgumentException(delegateInstance.getClass().getName() + \" doesn't implement \" + TaskListener.class);\n        }\n    }\n\n    // Activity Behavior\n    @Override\n    public void execute(DelegateExecution execution) {\n        ActivityExecution activityExecution = (ActivityExecution) execution;\n\n        if (Context.getProcessEngineConfiguration().isEnableProcessDefinitionInfoCache()) {\n            ObjectNode taskElementProperties = Context.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        }","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/helper/ClassDelegate.java#L116-L152","documentation":"ClassDelegate.getTaskListenerInstance instantiates the delegate class for a task listener and requires it to implement org.activiti.engine.delegate.TaskListener. Otherwise an ActivitiIllegalArgumentException naming the class is thrown.","triggerScenarios":"A task event fires on a task configured with class='...' whose class does not implement TaskListener; the class is instantiated lazily at notify() time so the error surfaces at runtime, not deployment.","commonSituations":"Pointing a user task's listener class attribute at an ExecutionListener or plain class; copy-pasting the class attribute from a service task.","solutions":["Make the class implement TaskListener and override notify(DelegateTask)","Fix the class attribute in the BPMN XML to reference a real TaskListener implementation","Add a unit test that instantiates the configured class and asserts it implements TaskListener"],"exampleFix":"// before\npublic class MyTaskHandler implements ExecutionListener { ... }\n// after\npublic class MyTaskHandler implements TaskListener {\n    public void notify(DelegateTask delegateTask) { ... }\n}","handlingStrategy":"validation","validationCode":"Class<?> c = Class.forName(listenerClassName);\nif (!TaskListener.class.isAssignableFrom(c)) {\n    throw new IllegalStateException(listenerClassName + \" must implement TaskListener\");\n}","typeGuard":"static boolean isValidTaskDelegate(Object o) {\n    return o instanceof TaskListener;\n}","tryCatchPattern":"try {\n    taskService.complete(taskId);\n} catch (org.activiti.engine.ActivitiIllegalArgumentException e) {\n    if (e.getMessage().contains(\"doesn't implement\")) {\n        // correct the task listener class attribute\n    }\n}","preventionTips":["Use distinct classes for execution listeners vs task listeners","Add smoke tests that fire each listener event type","Review BPMN XML class attributes during code review"],"tags":["classdelegate","tasklistener","type-mismatch","configuration"],"backgroundTag":"incompatible-source-type","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-18T11:17:12.947Z"}