flowable/flowable-engine · error · FlowableIllegalArgumentException

Cannot set global variables on execution

Error message

Cannot set global variables on execution '${executionId}', task is not part of process.

What it means

FlowableIllegalArgumentException thrown when a standalone task (not linked to any process execution) is asked to set 'global' (process-level) variables. Global variables require a parent process execution; a task without one has nowhere to store them.

Solutions

  1. Use scope=local in the request body so the variables are stored on the task itself.
  2. If process-global variables are intended, verify the task actually belongs to a process instance (GET /runtime/tasks/{id} and check processInstanceId).
  3. Route standalone-task variable writes to the task-scoped endpoint instead of the global-variable code path.
  4. Catch FlowableIllegalArgumentException (HTTP 400) and fall back to local-scope storage.

Example fix

// before
POST /runtime/tasks/{taskId}/variables
{"scope":"global","name":"orderId","value":"42"}
// after
POST /runtime/tasks/{taskId}/variables
{"scope":"local","name":"orderId","value":"42"}
Defensive patterns

Strategy: validation

Validate before calling

const task = await fetch(`/runtime/tasks/${taskId}`).then(r => r.json());
if (scope === 'global' && !task.processInstanceId) throw new Error('Standalone task: global variables not allowed');

Try / catch

try { /* set task variables */ } catch (e) {
  if (e.status === 400 && /task is not part of process/.test(e.message)) {
    // fall back to scope=local
  } else throw e;
}

Prevention

When it happens

Trigger: POST/PUT to /runtime/tasks/{taskId}/variables with scope=global where the task is standalone (created via the task service, not part of a process instance), so execution.getParentId() is null.

Common situations: Client code reuses a variable-update routine for both process and standalone tasks; task created via the tasks REST API then erroneously given process-level variables; process association removed/never established.

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


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

Appendix: source

Thrown at modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/process/BaseVariableCollectionResource.java:167

                        runtimeService.setVariablesLocal(execution.getId(), variablesToSet);
                        setVariables = runtimeService.getVariablesLocal(execution.getId(), variablesToSet.keySet());
                    }
                    
                } else {
                    if (execution.getParentId() != null) {
                        // Explicitly set on parent, setting non-local variables on execution itself will override local-variables if exists
                        
                        if (async) {
                            runtimeService.setVariablesAsync(execution.getParentId(), variablesToSet);
                            
                        } else {
                            runtimeService.setVariables(execution.getParentId(), variablesToSet);
                            setVariables = runtimeService.getVariables(execution.getParentId(), variablesToSet.keySet());
                        }
                        
                    } else {
                        // Standalone task, no global variables possible
                        throw new FlowableIllegalArgumentException("Cannot set global variables on execution '" + execution.getId() + "', task is not part of process.");
                    }
                }

                if (!async) {
                    for (RestVariable inputVariable : inputVariables) {
                        String variableName = inputVariable.getName();
                        Object variableValue = setVariables.get(variableName);
                        resultVariables.add(restResponseFactory.createRestVariable(variableName, variableValue, varScope, execution.getId(), variableType, false));
                    }
                }

            }
        }
        response.setStatus(HttpStatus.CREATED.value());
        return result;
    }

    protected void addGlobalVariables(Execution execution, Map<String, RestVariable> variableMap) {

View on GitHub (pinned to d6d39ce1c6)