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

  1. Make the resolved bean implement JavaDelegate (or ActivityBehavior) and rebuild/redeploy
  2. Verify the bean name in delegateExpression points to the intended delegate, not a helper/DTO bean
  3. If you want to call a method on a plain bean, use flowable:expression="${bean.method(exec)}" instead of delegateExpression
  4. 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

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


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)