flowable/flowable-engine · error · FlowableIllegalArgumentException

<delegateClassName> doesn't implement FlowableCollectionHand

Error message

<delegateClassName> doesn't implement FlowableCollectionHandler

What it means

ClassDelegateCollectionHandler instantiates the class configured as a collection handler for multi-instance activities and casts it to FlowableCollectionHandler. If the instance does not implement that interface, a FlowableIllegalArgumentException naming the class and the expected interface is thrown. The engine needs this interface to resolve the collection of items a multi-instance activity iterates over.

Source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/helper/ClassDelegateCollectionHandler.java:54

        super(className, fieldDeclarations);
    }
    
    public ClassDelegateCollectionHandler(Class<?> clazz, List<FieldDeclaration> fieldDeclarations) {
        super(clazz, fieldDeclarations);
    }

	@Override
	@SuppressWarnings("rawtypes")
	public Collection resolveCollection(Object collectionValue, DelegateExecution execution) {
		return getCollectionHandlerInstance().resolveCollection(collectionValue, execution);
	}

    protected FlowableCollectionHandler getCollectionHandlerInstance() {
        Object delegateInstance = instantiateDelegate(className, fieldDeclarations);
        if (delegateInstance instanceof FlowableCollectionHandler) {
            return (FlowableCollectionHandler) delegateInstance;
        } else {
            throw new FlowableIllegalArgumentException(delegateInstance.getClass().getName() + " doesn't implement " + FlowableCollectionHandler.class);
        }
    }
}

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Make the configured class implement org.flowable.engine.delegate.FlowableCollectionHandler (getCollection(DelegateExecution)).
  2. Verify the XML attribute points to the intended fully qualified handler class.
  3. If the collection is static or expression-based, use flowable:collection with an expression instead of a handler class.
  4. Redeploy the process application with the corrected handler.

Example fix

// before
public class MyCollection { public List<String> items() { ... } }
// after
public class MyCollection implements FlowableCollectionHandler {
    @Override public Collection<String> getCollection(DelegateExecution execution) { ... }
}
Defensive patterns

Strategy: validation

Validate before calling

Class<?> c = Class.forName(handlerClass);
if (!FlowableCollectionHandler.class.isAssignableFrom(c))
    throw new IllegalStateException("Collection handler must implement FlowableCollectionHandler");

Type guard

boolean isValidHandler(Object o) { return o instanceof FlowableCollectionHandler; }

Try / catch

try {
    runtimeService.startProcessInstanceByKey("proc");
} catch (FlowableIllegalArgumentException e) {
    if (e.getMessage().contains("FlowableCollectionHandler")) { /* fix handler class */ }
    throw e;
}

Prevention

When it happens

Trigger: A multi-instance activity declares a collection handler class (flowable:collectionHandler / delegateExpression style config) whose class does not implement org.flowable.engine.delegate.FlowableCollectionHandler; resolveCollection triggers the check.

Common situations: Using an ordinary List-returning bean class instead of a FlowableCollectionHandler implementation; wrong class name in the BPMN XML; refactoring removed the interface; stale deployment jar.

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/7d8d5968caa85ff1. Report an issue: GitHub.