flowable/flowable-engine · error · FlowableIllegalArgumentException

${className} does not implement the ${CmmnActivityBehavior.c

Error message

${className} does not implement the ${CmmnActivityBehavior.class} nor the ${PlanItemJavaDelegate.class} interface

What it means

getCmmnActivityBehavior resolves the class named by flowable:class into a CmmnActivityBehavior. If the instantiated object is neither a CmmnTriggerableActivityBehavior, a CmmnActivityBehavior, nor a PlanItemJavaDelegate, this FlowableIllegalArgumentException is thrown. It validates that plan-item behavior classes conform to the CMMN delegate contracts.

Source

Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/delegate/CmmnClassDelegate.java:95

    protected CmmnActivityBehavior getCmmnActivityBehavior(String className) {
        Object instance = instantiate(className);
        applyFieldExtensions(fieldExtensions, instance, false);

        if (instance instanceof PlanItemJavaDelegate) {
            return new PlanItemJavaDelegateActivityBehavior((PlanItemJavaDelegate) instance);

        } else if (instance instanceof PlanItemFutureJavaDelegate) {
            return new PlanItemFutureJavaDelegateActivityBehavior((PlanItemFutureJavaDelegate) instance);

        } else if (instance instanceof CmmnTriggerableActivityBehavior) {
            return (CmmnTriggerableActivityBehavior) instance;

        } else if (instance instanceof CmmnActivityBehavior) {
            return (CmmnActivityBehavior) instance;

        } else {
            throw new FlowableIllegalArgumentException(className + " does not implement the "
                    + 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 {

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Implement CmmnActivityBehavior (or PlanItemJavaDelegate for simple variable-returning logic, or CmmnTriggerableActivityBehavior if trigger support is needed) on the referenced class.
  2. For simple cases, replace the class reference with a delegate expression to a Spring/CDI bean implementing PlanItemJavaDelegate.
  3. Verify the fully-qualified class name in the CMMN XML points to the intended class.
  4. Check for duplicate classes on the classpath shadowing the intended implementation.

Example fix

// before
public class MyLogic implements org.flowable.engine.delegate.JavaDelegate {
  public void execute(DelegateExecution execution) { ... }
}
// after
public class MyLogic implements org.flowable.cmmn.api.delegate.PlanItemJavaDelegate {
  public Object execute(DelegatePlanItemInstance planItemInstance) { ... }
}
Defensive patterns

Strategy: validation

Validate before calling

Class<?> c = Class.forName(className);
boolean ok = org.flowable.cmmn.api.delegate.CmmnActivityBehavior.class.isAssignableFrom(c)
    || org.flowable.cmmn.api.delegate.PlanItemJavaDelegate.class.isAssignableFrom(c);
if (!ok) throw new IllegalStateException(className + " implements no CMMN behavior interface");

Type guard

boolean isValidCmmnBehavior(Object o) {
    return o instanceof org.flowable.cmmn.api.delegate.CmmnActivityBehavior
        || o instanceof org.flowable.cmmn.api.delegate.PlanItemJavaDelegate;
}

Try / catch

try {
    planItemExecution.proceed();
} catch (org.flowable.common.engine.api.FlowableIllegalArgumentException e) {
    if (e.getMessage().contains("nor the")) { log.error("Class {} is not a CMMN behavior", className); }
    throw e;
}

Prevention

When it happens

Trigger: Any CMMN plan item execution or trigger that resolves the class delegate: execute() or trigger() call getCmmnActivityBehavior(className), which calls instantiate(className) and type-checks the result. Triggered when the class implements none of the three accepted interfaces (e.g. it is a plain TaskListener, a BPMN JavaDelegate without PlanItemJavaDelegate, or an unrelated POJO).

Common situations: Pointing a CMMN task at a BPMN-style org.flowable.engine.delegate.JavaDelegate without adapting it to PlanItemJavaDelegate; configuring a listener class by copy/paste mistake; typo in the class name resolving to the wrong type in a shared package.

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/65de3627eb507703. Report an issue: GitHub.