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

  1. Make the class implement org.flowable.task.api.TaskListener (the interface referenced in the message) and add notify(DelegateTask).
  2. Check imports: use the TaskListener type shown in the error message, not a similarly named one from another module.
  3. If you intended a plan-item lifecycle listener or variable aggregator, move the class to the corresponding element/attribute instead of a task listener.
  4. 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

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


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