{"record":{"id":"73c459074e87aa17","repo":"flowable/flowable-engine","slug":"class-implementation-does-not-implement-varia","errorCode":null,"errorMessage":"Class ${implementation} does not implement ${VariableAggregator.class}","messagePattern":"Class (.+?) does not implement (.+?)","errorType":"validation","errorClass":"FlowableIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine/src/main/java/org/flowable/engine/impl/variable/BpmnAggregation.java","lineNumber":252,"sourceCode":"        variableInstance.setScopeId(scopeId);\n        variableInstance.setSubScopeId(subScopeId);\n        variableInstance.setScopeType(ScopeTypes.BPMN_VARIABLE_AGGREGATION);\n        variableServiceConfiguration.getVariableInstanceValueModifier().setVariableValue(variableInstance, value, tenantId);\n        return variableInstance;\n    }\n\n    public static Map<String, List<VariableInstance>> groupVariableInstancesByName(List<? extends VariableInstance> instances) {\n        return instances.stream().collect(Collectors.groupingBy(VariableInstance::getName));\n    }\n\n    public static VariableAggregator resolveVariableAggregator(VariableAggregationDefinition aggregation, DelegateExecution execution) {\n        if (ImplementationType.IMPLEMENTATION_TYPE_CLASS.equalsIgnoreCase(aggregation.getImplementationType())) {\n            Object delegate = ClassDelegateUtil.instantiateDelegate(aggregation.getImplementation(), null);\n            if (delegate instanceof VariableAggregator) {\n                return (VariableAggregator) delegate;\n            }\n\n            throw new FlowableIllegalArgumentException(\"Class \" + aggregation.getImplementation() + \" does not implement \" + VariableAggregator.class);\n        } else if (ImplementationType.IMPLEMENTATION_TYPE_DELEGATEEXPRESSION.equalsIgnoreCase(aggregation.getImplementationType())) {\n            Object delegate = DelegateExpressionUtil.resolveDelegateExpression(\n                    CommandContextUtil.getProcessEngineConfiguration().getExpressionManager().createExpression(aggregation.getImplementation()), execution);\n\n            if (delegate instanceof VariableAggregator) {\n                return (VariableAggregator) delegate;\n            }\n\n            throw new FlowableIllegalArgumentException(\n                    \"Delegate expression \" + aggregation.getImplementation() + \" did not resolve to an implementation of \" + VariableAggregator.class);\n        } else {\n            return CommandContextUtil.getProcessEngineConfiguration().getVariableAggregator();\n        }\n    }\n\n    public static void sortVariablesByCounter(List<VariableInstance> variableInstances, List<VariableInstance> counterVariableInstances) {\n        if (counterVariableInstances == null || counterVariableInstances.isEmpty()) {\n            return;","sourceCodeStart":234,"sourceCodeEnd":270,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine/src/main/java/org/flowable/engine/impl/variable/BpmnAggregation.java#L234-L270","documentation":"BpmnAggregation.resolveVariableAggregator instantiates the class named by the aggregation definition and requires it to implement org.flowable.variable.api.aggregation.VariableAggregator. When the class-delegate implementation instantiates to something else, this FlowableIllegalArgumentException is thrown.","triggerScenarios":"A collection variable aggregation definition with implementationType 'class' whose implementation class does not implement VariableAggregator; resolveVariableAggregator called via aggregator during aggregated variable handling.","commonSituations":"Pointing the aggregation at a generic Delegate/JavaDelegate class by copy-paste; refactoring that removed the interface; wrong import of a similarly named aggregator interface from another package/version.","solutions":["Make the implementation class implement org.flowable.variable.api.aggregation.VariableAggregator (add aggregate/aggregateResult methods).","Point the aggregation implementation at an existing VariableAggregator implementation instead.","If using delegateExpression, ensure the resolved bean also implements VariableAggregator (the same check applies).","Verify the Flowable version: older/custom aggregator interfaces differ; import the one from flowable-variable-service (org.flowable.variable.api.aggregation)."],"exampleFix":"// before\npublic class MyAggregator implements JavaDelegate { ... }\n// after\npublic class MyAggregator implements VariableAggregator {\n  public Object aggregate(VariableScopeScope, VariableAggregationContext ctx) { ... }\n  public Object aggregateResult(...) { ... }\n}","handlingStrategy":"validation","validationCode":"Class<?> c = Class.forName(implClassName);\nif (!VariableAggregator.class.isAssignableFrom(c)) throw new IllegalArgumentException(implClassName + \" must implement VariableAggregator\");","typeGuard":"boolean isAggregator(Class<?> c) { return VariableAggregator.class.isAssignableFrom(c); }","tryCatchPattern":"try { /* aggregation handling */ } catch (FlowableIllegalArgumentException e) { if (e.getMessage().contains(\"does not implement\")) log.error(\"Aggregation misconfig: {}\", e.getMessage()); else throw e; }","preventionTips":["Point aggregation definitions only at VariableAggregator implementations","Add a deployment-time check that aggregation classes implement the interface","Watch imports: use org.flowable.variable.api.aggregation.VariableAggregator, not similar names from other libs"],"tags":["flowable","bpmn","variable-aggregation","class-not-found","type-mismatch"],"backgroundTag":"invalid-argument-value","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-18T11:17:12.947Z"}