flowable/flowable-engine · error · FlowableIllegalArgumentException
Delegate expression did not resolve to an implementation of
Error message
Delegate expression ${handler.getImplementation()} did not resolve to an implementation of ${FlowableCollectionHandler.class} What it means
Thrown when resolving a multi-instance collectionHandler whose implementationType is 'delegate-expression': the delegate expression resolved successfully but the resulting object does not implement FlowableCollectionHandler, so the behavior has no way to obtain the collection.
Solutions
- Make the delegated class implement FlowableCollectionHandler (with its getCollection/resolveCollection methods) and redeploy/rebuild.
- Point the delegate-expression at a bean of the correct type.
- If you only need a static/dynamic list, use a plain collection expression or variable instead of a collection handler.
- Check the Flowable version: the handler interface package/name changed across versions; align imports with your engine version.
- Add a startup-time sanity check (bean instanceof FlowableCollectionHandler) in your Spring configuration.
Example fix
// before
class MyCollectionSupplier implements Supplier<Collection<String>> { ... }
// after
class MyCollectionSupplier implements FlowableCollectionHandler {
public Collection<?> getCollection(DelegateExecution execution) { ... }
} Defensive patterns
Strategy: type-guard
Validate before calling
Object bean = applicationContext.getBean("myCollectionHandler");
if (!(bean instanceof FlowableCollectionHandler)) {
throw new IllegalStateException("collectionHandler delegate must implement FlowableCollectionHandler");
} Type guard
boolean isFlowableCollectionHandler(Object delegate) {
return delegate instanceof FlowableCollectionHandler;
} Try / catch
try {
return task.execute(execution);
} catch (FlowableIllegalArgumentException ex) {
if (ex.getMessage().contains("FlowableCollectionHandler")) {
logger.error("collectionHandler delegate-expression resolved to wrong type: {}", ex.getMessage());
}
throw ex;
} Prevention
- Have all collection handler delegates implement FlowableCollectionHandler and verify with a startup assertion.
- Align the interface package/name with your engine version (it changed across Flowable releases).
- Use plain collection expressions/variables when a handler is unnecessary.
- Add a Spring context test asserting the bean type before deployment.
When it happens
Trigger: flowable:collectionHandler (or the case-variant) configured as a delegate-expression pointing at a bean/expression that resolves to an arbitrary object not implementing org.flowable.engine.impl.util (FlowableCollectionHandler), e.g. a plain List-producing bean or a wrong class.
Common situations: Delegate class implementing the wrong interface or an older/custom variant; bean registered in the Spring context of the wrong type; refactoring renamed/moved the interface so the class no longer implements it; pointing the delegate-expression at a utility method result instead of a handler bean.
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
- ' didn't resolve to a Collection
- completionCondition ' ' does not evaluate to a boolean value
- completionCondition ' ' does not evaluate to a boolean value
- Could not execute inner activity behavior of multi instance…
- Could not resolve loopCardinality expression
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/05a0f3f1f2e983e5.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/behavior/MultiInstanceActivityBehavior.java:655
activeValue = overrideValueNode.asString();
}
}
}
return activeValue;
}
protected FlowableCollectionHandler createFlowableCollectionHandler(CollectionHandler handler, DelegateExecution execution) {
FlowableCollectionHandler collectionHandler = null;
if (ImplementationType.IMPLEMENTATION_TYPE_CLASS.equalsIgnoreCase(handler.getImplementationType())) {
collectionHandler = new ClassDelegateCollectionHandler(handler.getImplementation(), null);
} else if (ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION.equalsIgnoreCase(handler.getImplementationType())) {
Object delegate = DelegateExpressionUtil.resolveDelegateExpression(CommandContextUtil.getProcessEngineConfiguration().getExpressionManager().createExpression(handler.getImplementation()), execution);
if (delegate instanceof FlowableCollectionHandler) {
collectionHandler = new DelegateExpressionCollectionHandler(execution, CommandContextUtil.getProcessEngineConfiguration().getExpressionManager().createExpression(handler.getImplementation()));
} else {
throw new FlowableIllegalArgumentException("Delegate expression " + handler.getImplementation() + " did not resolve to an implementation of " + FlowableCollectionHandler.class);
}
}
return collectionHandler;
}
// Getters and Setters
// ///////////////////////////////////////////////////////////
public Expression getLoopCardinalityExpression() {
return loopCardinalityExpression;
}
public void setLoopCardinalityExpression(Expression loopCardinalityExpression) {
this.loopCardinalityExpression = loopCardinalityExpression;
}
public String getCompletionCondition() {
return completionCondition;View on GitHub (pinned to d6d39ce1c6)