flowable/flowable-engine · error · FlowableIllegalArgumentException
Only allowed to update multiple variables in the same scope.
Error message
Only allowed to update multiple variables in the same scope.
What it means
All variables in one batch-creation request must target the same scope. createExecutionVariable records the scope of the first variable (defaulting to LOCAL) and throws FlowableIllegalArgumentException as soon as a later variable declares a different scope (GLOBAL vs LOCAL). Mixed-scope batches would make transactional semantics ambiguous, so they are rejected.
Solutions
- Split the batch into separate requests, one per scope (all GLOBAL in one call, all LOCAL in another)
- Set a uniform "scope" on every element of the array (or omit it so all default to LOCAL)
- Submit scope-specific variables through the dedicated endpoint (e.g. .../variables/{variableName} with scope in the body) instead of batching
Example fix
// before
[{"name":"a","scope":"global","value":1},{"name":"b","scope":"local","value":2}]
// after
[{"name":"a","scope":"global","value":1},{"name":"b","scope":"global","value":2}] // second batch with scope "local" sent separately Defensive patterns
Strategy: validation
Validate before calling
const scopes = new Set(variables.map(v => v.scope || 'local')); if (scopes.size > 1) throw new Error('batch contains mixed scopes: ' + [...scopes].join(',')); Type guard
function singleScope(vars) { const s = new Set(vars.map(v => v.scope || 'local')); return s.size <= 1; } Try / catch
try { await api.post(url, vars); } catch (e) { if (e.message.includes('same scope')) { for (const scope of ['global','local']) { const batch = vars.filter(v => (v.scope||'local') === scope); if (batch.length) await api.post(url, batch); } } } Prevention
- Group variables by scope before batching; issue one request per scope
- Omit "scope" entirely to accept the LOCAL default uniformly
- Enforce a uniform scope in your payload-building layer
When it happens
Trigger: POSTing a variables array like [{"name":"a","scope":"global"},{"name":"b","scope":"local"}] to a variables collection endpoint.
Common situations: Merging variables from two different contexts into one request; copying an example that used GLOBAL and appending LOCAL variables; generic UIs that let users pick scope per variable but batch-submit all at once.
Related errors
- Batch with id ' ' does not have a batch document.
- Cannot set global variables on execution
- Could not find a batch with id
- Execution ' ' does not have a variable ' ' in scope
- Failed to serialize to a RestVariable instance
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/971edd4c1a02c7c0.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/BaseVariableCollectionResource.java:126
RestVariableScope sharedScope = null;
RestVariableScope varScope = null;
Map<String, Object> variablesToSet = new HashMap<>();
for (RestVariable var : inputVariables) {
// Validate if scopes match
varScope = var.getVariableScope();
if (var.getName() == null) {
throw new FlowableIllegalArgumentException("Variable name is required");
}
if (varScope == null) {
varScope = RestVariableScope.LOCAL;
}
if (sharedScope == null) {
sharedScope = varScope;
}
if (varScope != sharedScope) {
throw new FlowableIllegalArgumentException("Only allowed to update multiple variables in the same scope.");
}
if (!override && hasVariableOnScope(execution, var.getName(), varScope)) {
throw new FlowableConflictException("Variable '" + var.getName() + "' is already present on execution '" + execution.getId() + "'.");
}
Object actualVariableValue = restResponseFactory.getVariableValue(var);
variablesToSet.put(var.getName(), actualVariableValue);
}
if (!variablesToSet.isEmpty()) {
if (restApiInterceptor != null) {
restApiInterceptor.createExecutionVariables(execution, variablesToSet, sharedScope);
}
Map<String, Object> setVariables = null;
if (sharedScope == RestVariableScope.LOCAL) {
View on GitHub (pinned to d6d39ce1c6)