flowable/flowable-engine · error · FlowableConflictException

Variable ' ' is already present on execution ' '.

Error message

Variable '${name}' is already present on execution '${executionId}'.

What it means

FlowableConflictException thrown when creating/updating variables on an execution without the 'override' flag while a variable with the same name already exists on that scope. The REST API refuses to silently overwrite an existing variable; callers must explicitly set override=true or use a different name.

Solutions

  1. Set the override query parameter to true on the request (e.g. POST .../variables?override=true) so existing variables are replaced.
  2. Remove or rename the duplicate variable from the request body.
  3. Before sending, GET the existing variables and only include ones not already present, or merge values client-side.
  4. Catch FlowableConflictException (HTTP 409) and decide per-variable whether to overwrite in a follow-up override call.

Example fix

// before
POST /runtime/process-instances/{id}/variables
[{"name":"orderId","value":"42"}]
// after
POST /runtime/process-instances/{id}/variables?override=true
[{"name":"orderId","value":"42"}]
Defensive patterns

Strategy: validation

Validate before calling

const existing = await fetch(`/runtime/process-instances/${pid}/variables`).then(r => r.json());
const existingNames = new Set(existing.map(v => v.name));
const dupes = body.variables.filter(v => existingNames.has(v.name));
if (dupes.length && !override) throw new Error(`Variables already present: ${dupes.map(d => d.name).join(',')}`);

Try / catch

try { /* setVariables call */ } catch (e) {
  if (e.status === 409 || /is already present on execution/.test(e.message)) {
    // re-issue with override=true or merge values
  } else throw e;
}

Prevention

When it happens

Trigger: POST/PUT to /runtime/process-instances/{id}/variables or /runtime/executions/{id}/variables with override=false (or absent) and a body containing a variable whose name already exists on the execution's scope.

Common situations: Re-submitting a variable-set request after a partial failure; a workflow engine or script that re-sets process variables on retry; two integrations writing the same variable name; client assumes PUT semantics (idempotent overwrite) but default override is false.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

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

            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) {
                    
                    if (async) {
                        runtimeService.setVariablesLocalAsync(execution.getId(), variablesToSet);
                        
                    } else {

View on GitHub (pinned to d6d39ce1c6)