flowable/flowable-engine · error · FlowableIllegalArgumentException
<delegateClassName> doesn't implement TaskListener
Error message
<delegateClassName> doesn't implement TaskListener
What it means
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.
Source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/helper/ClassDelegate.java:165
throw new FlowableIllegalArgumentException(delegateInstance.getClass().getName() + " doesn't implement " + TransactionDependentExecutionListener.class);
}
}
protected CustomPropertiesResolver getCustomPropertiesResolverInstance() {
Object delegateInstance = instantiateDelegate(className, fieldDeclarations);
if (delegateInstance instanceof CustomPropertiesResolver) {
return (CustomPropertiesResolver) delegateInstance;
} else {
throw new FlowableIllegalArgumentException(delegateInstance.getClass().getName() + " doesn't implement " + CustomPropertiesResolver.class);
}
}
protected TaskListener getTaskListenerInstance() {
Object delegateInstance = instantiateDelegate(className, fieldDeclarations);
if (delegateInstance instanceof TaskListener) {
return (TaskListener) delegateInstance;
} else {
throw new FlowableIllegalArgumentException(delegateInstance.getClass().getName() + " doesn't implement " + TaskListener.class);
}
}
protected TransactionDependentTaskListener getTransactionDependentTaskListenerInstance() {
Object delegateInstance = instantiateDelegate(className, fieldDeclarations);
if (delegateInstance instanceof TransactionDependentTaskListener) {
return (TransactionDependentTaskListener) delegateInstance;
} else {
throw new FlowableIllegalArgumentException(delegateInstance.getClass().getName() + " doesn't implement " + TransactionDependentTaskListener.class);
}
}
// Activity Behavior
@Override
public void execute(DelegateExecution execution) {
if (CommandContextUtil.getProcessEngineConfiguration().isEnableProcessDefinitionInfoCache()) {
ObjectNode taskElementProperties = BpmnOverrideContext.getBpmnOverrideElementProperties(serviceTaskId, execution.getProcessDefinitionId());
if (taskElementProperties != null && taskElementProperties.has(DynamicBpmnConstants.SERVICE_TASK_CLASS_NAME)) {View on GitHub (pinned to d6d39ce1c6)
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.
Example fix
// before
import org.activiti.api.task.runtime.events.listener.TaskEventListener;
public class MyTaskListener implements TaskEventListener { ... }
// after
import org.flowable.task.service.delegate.TaskListener;
public class MyTaskListener implements TaskListener {
@Override
public void notify(DelegateTask delegateTask) { ... }
} Defensive patterns
Strategy: validation
Validate before calling
Class<?> c = Class.forName(taskListenerClass);
if (!org.flowable.task.service.delegate.TaskListener.class.isAssignableFrom(c))
throw new IllegalStateException("Must implement Flowable TaskListener"); Type guard
boolean isValidTaskListener(Object o) { return o instanceof org.flowable.task.service.delegate.TaskListener; } Try / catch
try {
taskService.complete(taskId);
} catch (FlowableIllegalArgumentException e) {
if (e.getMessage().contains("TaskListener")) { /* fix listener class */ }
throw e;
} Prevention
- 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.
When it happens
Trigger: 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().
Common situations: 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.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- <delegateClassName> doesn't implement TransactionDependentTa
- Delegate expression ${expression} did not resolve to an impl
- <delegateClassName> doesn't implement TransactionDependentEx
- <delegateClassName> doesn't implement CustomPropertiesResolv
- <delegateClassName> doesn't implement JavaDelegate, FutureJa
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/e3e4ff7191339625.
Report an issue: GitHub.