{"record":{"id":"b9f05cff449ec3d1","repo":"flowable/flowable-engine","slug":"only-allowed-to-update-multiple-variables-in-the-s-b9f05c","errorCode":null,"errorMessage":"Only allowed to update multiple variables in the same scope.","messagePattern":"Only allowed to update multiple variables in the same scope\\.","errorType":"http","errorClass":"FlowableIllegalArgumentException","httpStatus":400,"severity":"error","filePath":"modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/task/TaskVariableCollectionResource.java","lineNumber":170,"sourceCode":"            RestVariableScope sharedScope = null;\n            RestVariableScope varScope = null;\n            Map<String, Object> variablesToSet = new HashMap<>();\n\n            for (RestVariable var : inputVariables) {\n                // Validate if scopes match\n                varScope = var.getVariableScope();\n                if (var.getName() == null) {\n                    throw new FlowableIllegalArgumentException(\"Variable name is required\");\n                }\n\n                if (varScope == null) {\n                    varScope = RestVariableScope.LOCAL;\n                }\n                if (sharedScope == null) {\n                    sharedScope = varScope;\n                }\n                if (varScope != sharedScope) {\n                    throw new FlowableIllegalArgumentException(\"Only allowed to update multiple variables in the same scope.\");\n                }\n\n                if (hasVariableOnScope(task, var.getName(), varScope)) {\n                    throw new FlowableConflictException(\"Variable '\" + var.getName() + \"' is already present on task '\" + task.getId() + \"'.\");\n                }\n\n                Object actualVariableValue = restResponseFactory.getVariableValue(var);\n                variablesToSet.put(var.getName(), actualVariableValue);\n            }\n\n            if (!variablesToSet.isEmpty()) {\n                if (restApiInterceptor != null) {\n                    restApiInterceptor.createTaskVariables(task, variablesToSet, sharedScope);\n                }\n\n                Map<String, Object> setVariables;\n                if (sharedScope == RestVariableScope.LOCAL) {\n                    taskService.setVariablesLocal(task.getId(), variablesToSet);","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/task/TaskVariableCollectionResource.java#L152-L188","documentation":"REST request validation in TaskVariableCollectionResource.createTaskVariable: the submitted variable list mixes LOCAL and GLOBAL scopes; a single bulk create is only allowed when all variables share one scope.","triggerScenarios":"POST /runtime/tasks/{taskId}/variables with [{\"name\":\"a\",\"variableScope\":\"local\"},{\"name\":\"b\",\"variableScope\":\"global\"}] (or one entry omitting scope, which defaults to local, alongside an explicit global).","commonSituations":"Bulk payloads assembled from mixed sources; forgetting the default-to-local behavior so an unscoped entry conflicts with an explicit global; splitting one variables map into scopes without grouping first.","solutions":["Make all entries use the same \"variableScope\" in one request","Split the payload into two requests: one for local, one for global","Omit \"variableScope\" everywhere to use the default (local)"],"exampleFix":"// before\n[{\"name\":\"a\",\"value\":1,\"variableScope\":\"local\"},{\"name\":\"b\",\"value\":2,\"variableScope\":\"global\"}]\n// after (two requests)\nPOST /variables [{\"name\":\"a\",\"value\":1,\"variableScope\":\"local\"},{\"name\":\"b\",\"value\":2,\"variableScope\":\"local\"}]","handlingStrategy":"validation","validationCode":"const scopes = new Set(variables.map(v => v.variableScope || 'local')); if (scopes.size > 1) { throw new Error('Split into per-scope requests: ' + [...scopes]); }","typeGuard":"function sameScope(vars) { return new Set(vars.map(v => v.variableScope || 'local')).size <= 1; }","tryCatchPattern":"try { await api.post(`/runtime/tasks/${taskId}/variables`, vars); } catch (e) { if (e.response && e.response.status === 400 && /same scope/.test(e.response.data.message || '')) { await Promise.all(groupByScope(vars).map(g => api.post(`/runtime/tasks/${taskId}/variables`, g))); } else { throw e; } }","preventionTips":["Group payloads by variableScope before posting","Remember omitted scope defaults to local","Either set variableScope explicitly on every entry or on none"],"tags":["rest-api","scope","batch"],"backgroundTag":"conflicting-config-options","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-18T11:17:12.947Z"}