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

  1. Make the class implement org.flowable.task.service.delegate.TaskListener (notify(DelegateTask)).
  2. Confirm the import is the Flowable TaskListener, not the Activiti or old Flowable 5 one.
  3. Verify the class attribute in the BPMN XML names the correct class.
  4. 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

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


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/e3e4ff7191339625. Report an issue: GitHub.