{"record":{"id":"05e6541ad425bca4","repo":"flowable/flowable-engine","slug":"cannot-aggregate-variable-varinstance","errorCode":null,"errorMessage":"Cannot aggregate variable: ${varInstance}","messagePattern":"Cannot aggregate variable: (.+?)","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/delegate/JsonPlanItemVariableAggregator.java","lineNumber":162,"sourceCode":"                        case JodaDateTimeType.TYPE_NAME:\n                        case UUIDType.TYPE_NAME:\n                            // For all these types it is OK to use toString as their string representation is what we want to have\n                            objectNode.put(targetVarName, varInstance.getValue().toString());\n                            break;\n                        case ByteArrayType.TYPE_NAME:\n                            objectNode.put(targetVarName, (byte[]) varInstance.getValue());\n                            break;\n                        default:\n                            if (PlanItemVariableAggregatorContext.OVERVIEW.equals(context.getState())) {\n                                // We can only use the aggregated variable if we are in an overview state\n                                Object value = varInstance.getValue();\n                                if (jsonMapper.isJsonNode(value)) {\n                                    objectNode.set(targetVarName, JsonUtil.asFlowableJsonNode(value));\n                                } else {\n                                    throw new FlowableException(\"Cannot aggregate overview variable: \" + varInstance);\n                                }\n                            } else {\n                                throw new FlowableException(\"Cannot aggregate variable: \" + varInstance);\n                            }\n                    }\n                }\n\n            }\n        }\n\n        return objectNode.getImplementationValue();\n    }\n\n    @Override\n    public Object aggregateMultiVariables(DelegatePlanItemInstance planItemInstance, List<? extends VariableInstance> instances,\n            PlanItemVariableAggregatorContext context) {\n        VariableJsonMapper objectMapper = cmmnEngineConfiguration.getVariableJsonMapper();\n        FlowableArrayNode arrayNode = objectMapper.createArrayNode();\n        for (VariableInstance instance : instances) {\n            arrayNode.add(JsonUtil.asFlowableJsonNode(instance.getValue()));\n        }","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/delegate/JsonPlanItemVariableAggregator.java#L144-L180","documentation":"In the same aggregator, when the aggregation context is not OVERVIEW, each collected instance value must still be a JSON node; if not, Flowable throws \"Cannot aggregate variable: \" + varInstance. The overview and non-overview branches are complementary: whichever context state applies, the value must be JSON-representable as a node.","triggerScenarios":"Repetition aggregation in a non-overview state (e.g. aggregating completed plan item variables into a result list) encounters an instance variable whose value is not a JSON node (plain String, Integer, POJO, byte[]).","commonSituations":"Delegates or scripts storing primitive/POJO values into variables that the aggregation configuration then collects; mixed variable types across repetitions; upgrading and changing what a delegate stores without migrating existing case variables.","solutions":["Store JSON node values for all variables included in repetition aggregation.","In the producing delegate/listener, wrap values with JsonUtil/JsonMapper before setVariable.","Exclude non-JSON variables from the aggregation configuration's variable list.","Migrate/normalize existing case variables to JSON for in-flight cases."],"exampleFix":"// before\nexecution.setVariable(\"score\", 42);\n// after\nObjectNode node = JsonUtil.createObjectNode();\nnode.put(\"score\", 42);\nexecution.setVariable(\"scoreData\", node);","handlingStrategy":"validation","validationCode":"Object value = varInstance.getValue();\nif (!(value instanceof com.fasterxml.jackson.databind.JsonNode)) {\n    throw new IllegalArgumentException(\"Aggregated variable must hold a JSON node, got: \" + value.getClass());\n}","typeGuard":"boolean canAggregate(VariableInstance v) {\n    return v.getValue() instanceof com.fasterxml.jackson.databind.JsonNode;\n}","tryCatchPattern":"try {\n    Object result = aggregator.aggregateSingleVariable(planItemInstance, context);\n} catch (org.flowable.common.engine.api.FlowableException e) {\n    if (e.getMessage().startsWith(\"Cannot aggregate variable\")) { log.error(\"Non-JSON value collected: {}\", e.getMessage()); }\n    throw e;\n}","preventionTips":["Enforce JSON typing for all repetition-collected variables via a shared variable-setting utility.","Audit scripts/delegates that set aggregation source variables for non-JSON writes.","Cover aggregation paths with integration tests using realistic variable values."],"tags":["java","cmmn","json","aggregation","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"}