flowable/flowable-engine · error · FlowableIllegalArgumentException
${delegateInstance.getClass().getName()} doesn't implement $
Error message
${delegateInstance.getClass().getName()} doesn't implement ${PlanItemVariableAggregator.class} What it means
Plan item variable aggregation configured via flowable:class is resolved by getPlanItemVariableAggregator, which requires the class to implement PlanItemVariableAggregator. If the instantiated object does not, this FlowableIllegalArgumentException is thrown when single- or multi-variable aggregation is invoked.
Source
Thrown at modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/delegate/CmmnClassDelegate.java:166
}
@Override
public Object aggregateSingleVariable(DelegatePlanItemInstance planItemInstance, PlanItemVariableAggregatorContext context) {
return getPlanItemVariableAggregator().aggregateSingleVariable(planItemInstance, context);
}
@Override
public Object aggregateMultiVariables(DelegatePlanItemInstance planItemInstance, List<? extends VariableInstance> instances, PlanItemVariableAggregatorContext context) {
return getPlanItemVariableAggregator().aggregateMultiVariables(planItemInstance, instances, context);
}
protected PlanItemVariableAggregator getPlanItemVariableAggregator() {
Object delegateInstance = instantiate(className);
applyFieldExtensions(fieldExtensions, delegateInstance, false);
if (delegateInstance instanceof PlanItemVariableAggregator) {
return (PlanItemVariableAggregator) delegateInstance;
} else {
throw new FlowableIllegalArgumentException(delegateInstance.getClass().getName() + " doesn't implement " + PlanItemVariableAggregator.class);
}
}
protected Object instantiate(String className) {
return ReflectUtil.instantiate(className);
}
public static void applyFieldExtensions(List<FieldExtension> fieldExtensions, Object target, boolean throwExceptionOnMissingField) {
if (fieldExtensions != null) {
for (FieldExtension fieldExtension : fieldExtensions) {
applyFieldExtension(fieldExtension, target, throwExceptionOnMissingField);
}
}
}
protected static void applyFieldExtension(FieldExtension fieldExtension, Object target, boolean throwExceptionOnMissingField) {
Object value = null;
if (fieldExtension.getExpression() != null) {View on GitHub (pinned to d6d39ce1c6)
Solutions
- Implement org.flowable.cmmn.api.runtime.PlanItemVariableAggregator (aggregateSingleVariable and aggregateMultiVariables) on the class.
- Alternatively use the built-in JsonPlanItemVariableAggregator by referencing it instead of a custom class.
- Verify the flowable:class attribute on the aggregation configuration points to the aggregator class.
- Rebuild/redeploy the custom aggregator so it truly implements the interface.
Example fix
// before
public class MyAggregator implements CmmnActivityBehavior { ... }
// after
public class MyAggregator implements PlanItemVariableAggregator {
public Object aggregateSingleVariable(DelegatePlanItemInstance p, PlanItemVariableAggregatorContext c) { ... }
public Map<String, Object> aggregateMultiVariables(DelegatePlanItemInstance p, PlanItemVariableAggregatorContext c) { ... }
} Defensive patterns
Strategy: validation
Validate before calling
Class<?> c = Class.forName(className);
if (!org.flowable.cmmn.api.runtime.PlanItemVariableAggregator.class.isAssignableFrom(c)) {
throw new IllegalStateException(className + " must implement PlanItemVariableAggregator");
} Type guard
boolean isAggregator(Object o) { return o instanceof org.flowable.cmmn.api.runtime.PlanItemVariableAggregator; } Try / catch
try {
Object aggregated = aggregator.aggregateSingleVariable(planItemInstance, context);
} catch (org.flowable.common.engine.api.FlowableIllegalArgumentException e) {
if (e.getMessage().contains("PlanItemVariableAggregator")) { log.error("Invalid aggregator class: {}", e.getMessage()); }
throw e;
} Prevention
- Prefer the built-in JsonPlanItemVariableAggregator unless custom aggregation is required.
- Test custom aggregators against the interface contract (single and multi variable methods).
- Verify aggregator class references in aggregation configuration during deployment checks.
When it happens
Trigger: A plan item (e.g. repetition with aggregation or a milestone/stage overview variable) declares an aggregator via flowable:class; aggregateSingleVariable or aggregateMultiVariables resolves the class and the object is not a PlanItemVariableAggregator.
Common situations: Using a JavaDelegate or behavior class as an aggregator by mistake; after upgrading Flowable, the old aggregator interface name changed; typo pointing at a similarly named class.
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
- ${className} does not implement the ${CmmnTriggerableActivit
- ${className} does not implement the ${CmmnActivityBehavior.c
- ${delegateInstance.getClass().getName()} doesn't implement $
- ${delegateInstance.getClass().getName()} doesn't implement $
- ${delegateInstance.getClass().getName()} doesn't implement $
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/210503f731e05d25.
Report an issue: GitHub.