{"record":{"id":"70c18cef629d102b","repo":"flowable/flowable-engine","slug":"cannot-aggregate-overview-variable-varinstance","errorCode":null,"errorMessage":"Cannot aggregate overview variable: ${varInstance}","messagePattern":"Cannot aggregate overview 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":159,"sourceCode":"                        case LocalDateType.TYPE_NAME:\n                        case LocalDateTimeType.TYPE_NAME:\n                        case JodaDateType.TYPE_NAME:\n                        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();","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-cmmn-engine/src/main/java/org/flowable/cmmn/engine/impl/delegate/JsonPlanItemVariableAggregator.java#L141-L177","documentation":"JsonPlanItemVariableAggregator.aggregateSingleVariable builds an overview aggregate variable from the values of repeated plan items. In the OVERVIEW context state, each collected instance's value must be a JSON node; when varInstance's value is not a JSON node, this FlowableException is thrown because the value cannot be placed into the overview JSON object.","triggerScenarios":"A plan item repetition defines aggregation into a variable in OVERVIEW state (e.g. stage/milestone overview with completion/available counts), and one of the aggregated instance variables holds a non-JSON value (String, number, POJO, null serialized type) instead of a Flowable-JSON node.","commonSituations":"Custom variable writers storing plain Java objects or primitives into the aggregated variable; a previous state stored a simple type that later gets re-aggregated in overview; mixing custom delegates that set non-JSON values.","solutions":["Ensure every variable aggregated in overview state stores a JSON node value (use JsonUtil/create Flowable JSON values when setting the variable).","Convert the value to JSON before storing it, e.g. via jsonMapper/JsonUtil.asFlowableJsonNode in the producing delegate.","Adjust the aggregation configuration to target variables that are guaranteed JSON-typed.","Add a wrapper delegate that normalizes non-JSON values into JSON nodes before aggregation."],"exampleFix":"// before\nplanItemInstance.setVariable(\"result\", \"someString\");\n// after\nplanItemInstance.setVariable(\"result\", JsonUtil.createObjectNode().put(\"value\", \"someString\"));","handlingStrategy":"validation","validationCode":"Object value = varInstance.getValue();\nif (!(value instanceof com.fasterxml.jackson.databind.JsonNode)) {\n    value = JsonUtil.asFlowableJsonNode(value); // or reject before aggregation\n}","typeGuard":"boolean isJsonValued(VariableInstance v) {\n    return v != null && (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 overview variable\")) { log.error(\"Non-JSON value in overview aggregation: {}\", e.getMessage()); }\n    throw e;\n}","preventionTips":["Only write JSON node values into variables included in repetition aggregation.","Normalize values with JsonUtil at variable-creation time, not at aggregation time.","Document which variables your aggregation config consumes and enforce their type."],"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"}