flowable/flowable-engine · error · FlowableIllegalArgumentException
Cannot set global variable '
Error message
Cannot set global variable '
What it means
FlowableIllegalArgumentException thrown in setVariable when attempting to set a variable with GLOBAL scope on a standalone CMMN task that is not linked to a case (no scopeId). Standalone tasks cannot hold global/process-level variables; only local task variables are allowed. If the task IS part of a case, the variable is set on the case instance via runtimeService.
Source
Thrown at modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/task/TaskVariableBaseResource.java:250
if (restApiInterceptor != null) {
if (isNew) {
restApiInterceptor.createTaskVariables(task, Collections.singletonMap(name, value), scope);
} else {
restApiInterceptor.updateTaskVariables(task, Collections.singletonMap(name, value), scope);
}
}
if (scope == RestVariableScope.LOCAL) {
taskService.setVariableLocal(task.getId(), name, value);
} else {
if (ScopeTypes.CMMN.equals(task.getScopeType()) && task.getScopeId() != null) {
// Explicitly set on execution, setting non-local variable on
// task will override local-variable if exists
runtimeService.setVariable(task.getScopeId(), name, value);
} else {
// Standalone task, no global variables possible
throw new FlowableIllegalArgumentException("Cannot set global variable '" + name + "' on task '" + task.getId() + "', task is not part of process.");
}
}
}
}
View on GitHub (pinned to d6d39ce1c6)
Solutions
- Omit the scope field or set scope=local for standalone tasks
- Only use scope=global when the task belongs to a case instance
- Query the task first to confirm scopeId is set before sending global-scoped variables
Example fix
// before
{"name":"v","value":1,"scope":"global"} // standalone task
// after
{"name":"v","value":1,"scope":"local"} (or omit scope) Defensive patterns
Strategy: validation
Validate before calling
const task = await getTask(taskId);
if (scope === 'global' && !task.scopeId) throw new Error(`task ${taskId} is standalone; global scope is not allowed`); Type guard
const canSetGlobal = (task) => task != null && typeof task.scopeId === 'string' && task.scopeId.length > 0;
Try / catch
try { await setVariable({...v, scope:'global'}) } catch (e) { if (/Cannot set global variable/.test(e.message)) return setVariable({...v, scope:'local'}); throw e; } Prevention
- Default to scope='local' unless the task belongs to a case instance
- Fetch the task first and check scopeId before global writes
- Don't blanket-copy scope settings from process-task scripts
When it happens
Trigger: POST/PUT with scope=global on a standalone task (task.getScopeId() == null) — Flowable falls into the else branch and rejects the operation.
Common situations: Clients blanket-applying scope:'global' to all variable calls; migrating REST scripts from process-task usage to standalone task usage; misunderstanding that standalone tasks have no case instance to attach global variables to.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Invalid variable scope: '${scope}'
- The variable does not have a binary data stream.
- Plan item instance '${id}' does not have a variable '${varia
- Only 'binary' and 'serializable' are supported as variable t
- Setting variable is not supported for read only delegate exe
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/7179d79a024c0c17.
Report an issue: GitHub.