{"record":{"id":"210503f731e05d25","repo":"flowable/flowable-engine","slug":"delegateinstance-getclass-getname-doesn-t-i-210503","errorCode":null,"errorMessage":"${delegateInstance.getClass().getName()} doesn't implement ${PlanItemVariableAggregator.class}","messagePattern":"(.+?) doesn't implement (.+?)","errorType":"validation","errorClass":"FlowableIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/delegate/CmmnClassDelegate.java","lineNumber":166,"sourceCode":"    }\n\n    @Override\n    public Object aggregateSingleVariable(DelegatePlanItemInstance planItemInstance, PlanItemVariableAggregatorContext context) {\n        return getPlanItemVariableAggregator().aggregateSingleVariable(planItemInstance, context);\n    }\n\n    @Override\n    public Object aggregateMultiVariables(DelegatePlanItemInstance planItemInstance, List<? extends VariableInstance> instances, PlanItemVariableAggregatorContext context) {\n        return getPlanItemVariableAggregator().aggregateMultiVariables(planItemInstance, instances, context);\n    }\n\n    protected PlanItemVariableAggregator getPlanItemVariableAggregator() {\n        Object delegateInstance = instantiate(className);\n        applyFieldExtensions(fieldExtensions, delegateInstance, false);\n        if (delegateInstance instanceof PlanItemVariableAggregator) {\n            return (PlanItemVariableAggregator) delegateInstance;\n        } else {\n            throw new FlowableIllegalArgumentException(delegateInstance.getClass().getName() + \" doesn't implement \" + PlanItemVariableAggregator.class);\n        }\n    }\n\n    protected Object instantiate(String className) {\n        return ReflectUtil.instantiate(className);\n    }\n\n    public static void applyFieldExtensions(List<FieldExtension> fieldExtensions, Object target, boolean throwExceptionOnMissingField) {\n        if (fieldExtensions != null) {\n            for (FieldExtension fieldExtension : fieldExtensions) {\n                applyFieldExtension(fieldExtension, target, throwExceptionOnMissingField);\n            }\n        }\n    }\n\n    protected static void applyFieldExtension(FieldExtension fieldExtension, Object target, boolean throwExceptionOnMissingField) {\n        Object value = null;\n        if (fieldExtension.getExpression() != null) {","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/delegate/CmmnClassDelegate.java#L148-L184","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\npublic class MyAggregator implements CmmnActivityBehavior { ... }\n// after\npublic class MyAggregator implements PlanItemVariableAggregator {\n  public Object aggregateSingleVariable(DelegatePlanItemInstance p, PlanItemVariableAggregatorContext c) { ... }\n  public Map<String, Object> aggregateMultiVariables(DelegatePlanItemInstance p, PlanItemVariableAggregatorContext c) { ... }\n}","handlingStrategy":"validation","validationCode":"Class<?> c = Class.forName(className);\nif (!org.flowable.cmmn.api.runtime.PlanItemVariableAggregator.class.isAssignableFrom(c)) {\n    throw new IllegalStateException(className + \" must implement PlanItemVariableAggregator\");\n}","typeGuard":"boolean isAggregator(Object o) { return o instanceof org.flowable.cmmn.api.runtime.PlanItemVariableAggregator; }","tryCatchPattern":"try {\n    Object aggregated = aggregator.aggregateSingleVariable(planItemInstance, context);\n} catch (org.flowable.common.engine.api.FlowableIllegalArgumentException e) {\n    if (e.getMessage().contains(\"PlanItemVariableAggregator\")) { log.error(\"Invalid aggregator class: {}\", e.getMessage()); }\n    throw e;\n}","preventionTips":["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."],"tags":["java","cmmn","aggregator","flowable"],"backgroundTag":"type-mismatch","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}