flowable/flowable-engine · error · FlowableIllegalArgumentException
Delegate expression ${expression} did not resolve to an impl
Error message
Delegate expression ${expression} did not resolve to an implementation of ${TaskListener.class} What it means
DelegateExpressionTaskListener resolves a delegate expression against a DelegateTask and expects the result to implement TaskListener. When the resolved object is not a TaskListener it throws FlowableIllegalArgumentException. Same guard family as the case/plan-item delegate listeners, applied to task listeners.
Source
Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/listener/DelegateExpressionTaskListener.java:44
*/
public class DelegateExpressionTaskListener implements TaskListener {
protected Expression expression;
protected List<FieldExtension> fieldExtensions;
public DelegateExpressionTaskListener(Expression expression, List<FieldExtension> fieldExtensions) {
this.expression = expression;
this.fieldExtensions = fieldExtensions;
}
@Override
public void notify(DelegateTask delegateTask) {
Object delegate = DelegateExpressionUtil.resolveDelegateExpression(expression, delegateTask, fieldExtensions);
if (delegate instanceof TaskListener taskListener) {
taskListener.notify(delegateTask);
} else {
throw new FlowableIllegalArgumentException("Delegate expression " + expression + " did not resolve to an implementation of " + TaskListener.class);
}
}
/**
* returns the expression text for this task listener.
*/
public String getExpressionText() {
return expression.getExpressionText();
}
}
View on GitHub (pinned to d6d39ce1c6)
Solutions
- Make the delegate implement org.flowable.task.service.delegate.TaskListener (the CMMN one).
- Verify you are not mixing the BPMN engine's TaskListener interface with the CMMN one — a very common cause.
- Fix the expression to reference the correct bean name/type.
- Add a unit test resolving each delegate expression and asserting the expected interface.
Example fix
// before
public class MyListener implements org.flowable.engine.delegate.TaskListener { ... } // BPMN interface
// after
public class MyListener implements org.flowable.task.service.delegate.TaskListener {
public void notify(DelegateTask delegateTask) { /* ... */ }
} Defensive patterns
Strategy: type-guard
Validate before calling
Object delegate = DelegateExpressionUtil.resolveDelegateExpression(expression, delegateTask, null);
if (!(delegate instanceof org.flowable.task.service.delegate.TaskListener)) {
throw new IllegalArgumentException("Expression must resolve to a CMMN TaskListener");
} Type guard
boolean isCmmnTaskListener(Object o) {
return o instanceof org.flowable.task.service.delegate.TaskListener;
} Try / catch
try {
// task creation triggers listeners
} catch (FlowableIllegalArgumentException e) {
if (e.getMessage() != null && e.getMessage().contains("TaskListener")) {
throw new ConfigurationException("Delegate for " + expression + " must implement the CMMN TaskListener", e);
}
throw e;
} Prevention
- Beware BPMN vs CMMN TaskListener interfaces with identical names — import carefully
- Test delegate expression resolution for each listener in a unit test
- Rename beans per engine module to avoid cross-wiring
When it happens
Trigger: notify(delegateTask) resolves the expression and the object fails `instanceof TaskListener` — the expression points at a bean or value that is not a task listener.
Common situations: Spring bean exposed under the referenced name has the wrong type; a BPMN TaskListener (org.flowable.engine.delegate.TaskListener) is referenced where the CMMN TaskListener is required; expression typo returning a scalar.
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
- Delegate expression ${expression} did not resolve to an impl
- Delegate expression ${expression} did not resolve to an impl
- Delegate expression " + expression + " did not resolve to an
- Delegate expression ${expression} did not resolve to an impl
- Delegate expression ${expression} did not resolve to an impl
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/6e25fc103b28451f.
Report an issue: GitHub.