flowable/flowable-engine · error · ActivitiIllegalArgumentException
Delegate expression did neither resolve to an…
Error message
Delegate expression ${expression} did neither resolve to an implementation of ${ActivityBehavior.class} nor ${JavaDelegate.class} What it means
Thrown when a delegate expression on a service task resolves to an object that is neither an ActivityBehavior nor a JavaDelegate. The engine cannot know how to execute the resolved bean, so it rejects it with this ActivitiIllegalArgumentException before dispatching.
Solutions
- Make the resolved bean implement JavaDelegate (or ActivityBehavior) and rebuild/redeploy
- Verify the bean name in delegateExpression points to the intended delegate, not a helper/DTO bean
- If you want to call a method on a plain bean, use flowable:expression="${bean.method(exec)}" instead of delegateExpression
- Check Spring component scanning so the right class is exposed under that bean name
Example fix
// before
public class ApproveTaskHelper {
public void approve(DelegateExecution e) { /* ... */ }
}
<serviceTask flowable:delegateExpression="${approveTaskHelper}" />
// after
public class ApproveTaskHelper implements JavaDelegate {
public void execute(DelegateExecution e) { /* ... */ }
}
<serviceTask flowable:delegateExpression="${approveTaskHelper}" /> Defensive patterns
Strategy: validation
Validate before calling
Object bean = applicationContext.getBean("approveTaskHelper");
if (!(bean instanceof JavaDelegate) && !(bean instanceof ActivityBehavior)) {
throw new IllegalStateException(
"delegateExpression bean must implement JavaDelegate or ActivityBehavior");
} Type guard
public static boolean isValidDelegate(Object o) {
return o instanceof JavaDelegate || o instanceof ActivityBehavior;
} Try / catch
try {
runtimeService.startProcessInstanceByKey(key, vars);
} catch (org.activiti.engine.ActivitiIllegalArgumentException e) {
if (e.getMessage().contains("did neither resolve to an implementation of")) {
// wrong bean type bound to delegateExpression; fix bean wiring
} else { throw e; }
} Prevention
- Adopt the convention: delegateExpression targets JavaDelegate beans only; use expression for method calls
- Add a startup check (or test) asserting every delegateExpression bean implements JavaDelegate
- Grep BPMN files for delegateExpression and verify each bean name exists and its type
- After refactoring a delegate class, redeploy the process definition and re-run integration tests
When it happens
Trigger: flowable:delegateExpression="${someBean}" where someBean resolves to a plain POJO, a String, or a wrong type (e.g. an Expression-returning bean) that implements neither ActivityBehavior nor JavaDelegate; also occurs when the class was refactored and no longer implements JavaDelegate.
Common situations: Spring bean registered with the wrong class or interface after a refactor; typo pointing the delegateExpression at a helper bean instead of the delegate; migrating from Activiti 5 where a custom interface was accepted; using ${} on a method instead of a bean reference (should be flowable:expression).
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
- Custom properties resolver delegate expression " +…
- Delegate expression + expression + did neither resolve to…
- Delegate expression " + expression + " did not resolve to…
- Delegate expression " + expression + " did not resolve to…
- Delegate expression " + expression + " did not resolve to…
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/29e30085b5f1e5db.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/behavior/ServiceTaskDelegateExpressionActivityBehavior.java:107
}
Object delegate = DelegateExpressionUtil.resolveDelegateExpression(expression, execution, fieldDeclarations);
if (delegate instanceof ActivityBehavior) {
if (delegate instanceof AbstractBpmnActivityBehavior) {
((AbstractBpmnActivityBehavior) delegate).setMultiInstanceActivityBehavior(getMultiInstanceActivityBehavior());
}
Context.getProcessEngineConfiguration().getDelegateInterceptor()
.handleInvocation(new ActivityBehaviorInvocation((ActivityBehavior) delegate, activityExecution));
} else if (delegate instanceof JavaDelegate) {
Context.getProcessEngineConfiguration().getDelegateInterceptor().handleInvocation(new JavaDelegateInvocation((JavaDelegate) delegate, execution));
leave(activityExecution);
} else {
throw new ActivitiIllegalArgumentException("Delegate expression " + expression + " did neither resolve to an implementation of "
+ ActivityBehavior.class + " nor " + JavaDelegate.class);
}
} else {
leave(activityExecution);
}
} catch (Exception exc) {
Throwable cause = exc;
BpmnError error = null;
while (cause != null) {
if (cause instanceof BpmnError) {
error = (BpmnError) cause;
break;
} else if (cause instanceof RuntimeException) {
if (ErrorPropagation.mapException((RuntimeException) cause, activityExecution, mapExceptions)) {
return;
}View on GitHub (pinned to d6d39ce1c6)