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
- Implement CmmnActivityBehavior (or PlanItemJavaDelegate for simple variable-returning logic, or CmmnTriggerableActivityBehavior if trigger support is needed) on the referenced class.
- For simple cases, replace the class reference with a delegate expression to a Spring/CDI bean implementing PlanItemJavaDelegate.
- Verify the fully-qualified class name in the CMMN XML points to the intended class.
- 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
- Use PlanItemJavaDelegate for simple logic — it is the CMMN counterpart of JavaDelegate.
- Keep BPMN and CMMN delegate packages separate to avoid wrong imports.
- Write a model-conformance test validating all flowable:class values at deploy time.
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
- ${className} does not implement the ${CmmnTriggerableActivit
- ${delegateInstance.getClass().getName()} doesn't implement $
- ${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/65de3627eb507703.
Report an issue: GitHub.