flowable/flowable-engine · error · FlowableIllegalArgumentException
${delegateInstance.getClass().getName()} doesn't implement $
Error message
${delegateInstance.getClass().getName()} doesn't implement ${TaskListener.class} What it means
When a CMMN case element declares a task listener via flowable:class, CmmnClassDelegate.getTaskListenerInstance instantiates the class, applies field extensions, and requires it to implement the TaskListener interface. If it does not, this FlowableIllegalArgumentException is thrown with the actual class name and the missing interface.
Source
Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/delegate/CmmnClassDelegate.java:114
+ CmmnActivityBehavior.class + " nor the " + PlanItemJavaDelegate.class + " interface");
}
}
@Override
public void notify(DelegateTask delegateTask) {
TaskListener taskListenerInstance = getTaskListenerInstance(delegateTask);
taskListenerInstance.notify(delegateTask);
}
protected TaskListener getTaskListenerInstance(DelegateTask delegateTask) {
Object delegateInstance = instantiate(className);
applyFieldExtensions(fieldExtensions, delegateInstance, false);
if (delegateInstance instanceof TaskListener) {
return (TaskListener) delegateInstance;
} else {
throw new FlowableIllegalArgumentException(delegateInstance.getClass().getName() + " doesn't implement " + TaskListener.class);
}
}
@Override
public void stateChanged(DelegatePlanItemInstance planItemInstance, String oldState, String newState) {
PlanItemInstanceLifecycleListener planItemLifeCycleListenerInstance = getPlanItemLifeCycleListenerInstance();
planItemLifeCycleListenerInstance.stateChanged(planItemInstance, oldState, newState);
}
@Override
public void stateChanged(CaseInstance caseInstance, String oldState, String newState) {
CaseInstanceLifecycleListener caseLifeCycleListenerInstance = getCaseLifeCycleListenerInstance();
caseLifeCycleListenerInstance.stateChanged(caseInstance, oldState, newState);
}
protected PlanItemInstanceLifecycleListener getPlanItemLifeCycleListenerInstance() {
Object delegateInstance = instantiate(className);
applyFieldExtensions(fieldExtensions, delegateInstance, false);View on GitHub (pinned to d6d39ce1c6)
Solutions
- Make the class implement org.flowable.task.api.TaskListener (the interface referenced in the message) and add notify(DelegateTask).
- Check imports: use the TaskListener type shown in the error message, not a similarly named one from another module.
- If you intended a plan-item lifecycle listener or variable aggregator, move the class to the corresponding element/attribute instead of a task listener.
- Rebuild/redeploy so the deployed class actually implements the interface.
Example fix
// before
import org.flowable.engine.delegate.TaskListener;
public class MyListener implements TaskListener { ... }
// after
import org.flowable.task.api.TaskListener;
public class MyListener implements TaskListener {
public void notify(DelegateTask delegateTask) { ... }
} Defensive patterns
Strategy: validation
Validate before calling
Class<?> c = Class.forName(className);
if (!org.flowable.task.api.TaskListener.class.isAssignableFrom(c)) {
throw new IllegalStateException(className + " must implement TaskListener");
} Type guard
boolean isTaskListener(Object o) { return o instanceof org.flowable.task.api.TaskListener; } Try / catch
try {
taskListener.notify(delegateTask);
} catch (org.flowable.common.engine.api.FlowableIllegalArgumentException e) {
if (e.getMessage().contains("doesn't implement")) { log.error("Not a TaskListener: {}", e.getMessage()); }
throw e;
} Prevention
- Import TaskListener from the package shown in the error message — engine modules have similarly named interfaces.
- Add a unit test asserting each configured listener class implements TaskListener.
- After Flowable version upgrades, recheck listener imports.
When it happens
Trigger: A plan item (typically human task) declares <flowable:task-listener flowable:class="..."/>, and the listener is first requested via taskListenerInstance(); the instantiated class does not implement Cmmn TaskListener.
Common situations: Using the BPMN engine TaskListener (org.flowable.engine.delegate.TaskListener) instead of the CMMN one; implementing the wrong listener type (lifecycle listener) in the class attribute; after a Flowable version migration the TaskListener package changed.
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
- ${className} does not implement the ${CmmnTriggerableActivit
- ${className} does not implement the ${CmmnActivityBehavior.c
- ${delegateInstance.getClass().getName()} doesn't implement $
- ${delegateInstance.getClass().getName()} doesn't implement $
- ${delegateInstance.getClass().getName()} doesn't implement $
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/5c3447623dcd2c45.
Report an issue: GitHub.