flowable/flowable-engine · error · FlowableException

Cannot aggregate variable

Error message

Cannot aggregate variable: ${varInstance}

What it means

Same aggregation path as the overview error but thrown when aggregation is NOT in OVERVIEW state and the variable value is not a JSON node. The aggregator only supports JSON-typed values in this branch of aggregateSingleVariable.

Solutions

  1. Store the aggregated variables as JSON nodes rather than plain Java types
  2. Verify which JsonMapper is configured and that it recognizes your variable values as JSON
  3. Filter variables before aggregation so only JSON variables reach the aggregator
  4. Wrap primitive values into a JSON object structure before setting them as variables

Example fix

// before
execution.setVariable("status", "DONE");
// after
execution.setVariable("status", JsonUtil.createChildObjectNode(null, "status", "DONE").get("status"));
Defensive patterns

Strategy: type-guard

Validate before calling

for (VariableInstance vi : varInstances) {
    if (!jsonMapper.isJsonNode(vi.getValue())) {
        throw new IllegalStateException("Variable " + vi.getName() + " is not JSON");
    }
}

Type guard

boolean isJsonVariable(VariableInstance vi, FlowableJsonMapper m) {
    return m.isJsonNode(vi.getValue());
}

Try / catch

try {
    result = aggregator.aggregateSingleVariable(ctx, varInstances);
} catch (FlowableException e) {
    logger.warn("Skipping non-JSON aggregation input: " + e.getMessage());
}

Prevention

When it happens

Trigger: Non-overview aggregation state receiving a variable instance whose value fails jsonMapper.isJsonNode(value) — e.g. a String, POJO or byte[] variable supplied to the JsonVariableAggregator.

Common situations: Child-process variables of simple types (String, Integer) collected by the JSON aggregator during parallel process-instance migrations or aggregation delegates.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/a23cff1e6a7b425b. Report an issue: GitHub.

Appendix: source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/delegate/JsonVariableAggregator.java:163

                        case JodaDateTimeType.TYPE_NAME:
                        case UUIDType.TYPE_NAME:
                            // For all these types it is OK to use toString as their string representation is what we want to have
                            objectNode.put(targetVarName, varInstance.getValue().toString());
                            break;
                        case ByteArrayType.TYPE_NAME:
                            objectNode.put(targetVarName, (byte[]) varInstance.getValue());
                            break;
                        default:
                            if (VariableAggregatorContext.OVERVIEW.equals(context.getState())) {
                                // We can only use the aggregated variable if we are in an overview state
                                Object value = varInstance.getValue();
                                if (jsonMapper.isJsonNode(value)) {
                                    objectNode.set(targetVarName, JsonUtil.asFlowableJsonNode(value));
                                } else {
                                    throw new FlowableException("Cannot aggregate overview variable: " + varInstance);
                                }
                            } else {
                                throw new FlowableException("Cannot aggregate variable: " + varInstance);
                            }
                    }
                }

            }
        }

        return objectNode.getImplementationValue();
    }

    @Override
    public Object aggregateMultiVariables(DelegateExecution execution, List<? extends VariableInstance> instances, VariableAggregatorContext context) {
        VariableJsonMapper objectMapper = processEngineConfiguration.getVariableJsonMapper();
        FlowableArrayNode arrayNode = objectMapper.createArrayNode();
        for (VariableInstance instance : instances) {
            arrayNode.add(JsonUtil.asFlowableJsonNode(instance.getValue()));
        }

View on GitHub (pinned to d6d39ce1c6)