flowable/flowable-engine · error · FlowableConflictException

Local variable ' ' is already present on plan item instance…

Error message

Local variable '${name}' is already present on plan item instance '${instanceId}'.

What it means

When creating a LOCAL variable via the CMMN REST API with the 'new variable' semantics (isNew) and async flag path, Flowable first checks runtimeService.hasLocalVariable; if a local variable with that name already exists on the plan item instance, it throws FlowableConflictException (HTTP 409) instead of silently overwriting. This protects callers from accidentally clobbering existing local variables.

Solutions

  1. Use PUT (update) on the existing variable instead of POST create if overwriting is intended
  2. Check existence first via GET /cmmn-runtime/plan-item-instances/{id}/variables/{name} and choose POST or PUT accordingly
  3. Use a different variable name, or remove the existing local variable before recreating
  4. Treat HTTP 409 as 'already exists' in client retry logic and switch to update

Example fix

// before: always POST
post(variablesUrl, newVariable(name, value, LOCAL));
// after
if (!exists(variablesUrl + "/" + name)) {
    post(variablesUrl, newVariable(name, value, LOCAL));
} else {
    put(variablesUrl + "/" + name, newVariable(name, value, LOCAL));
}
Defensive patterns

Strategy: validation

Validate before calling

boolean exists = restTemplate.getForObject(
    base + "/cmmn-runtime/plan-item-instances/" + planItemId + "/variables/" + name, Boolean.class) != null;
if (exists) {
    // update via PUT instead of POST create
}

Type guard

null

Try / catch

try {
    postLocalVariable(planItemId, name, value);
} catch (HttpClientErrorException.Conflict e) {
    putLocalVariable(planItemId, name, value); // fall back to update
}

Prevention

When it happens

Trigger: POSTing a new local variable to /cmmn-runtime/plan-item-instances/{id}/variables with scope=local for a variable name that already exists locally on that plan item instance, when isNew is true.

Common situations: Retry logic re-POSTing a variable that was already created in a previous attempt, concurrent clients creating the same variable name, scripts that assume variables are upserted when the create endpoint is actually create-only.

Related errors


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

Appendix: source

Thrown at modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/caze/BaseVariableResource.java:403

            throw new FlowableIllegalArgumentException("Could not process multipart content", ioe);
            
        } catch (ClassNotFoundException ioe) {
            throw new FlowableContentNotSupportedException(
                    "The provided body contains a serialized object for which the class was not found: " + ioe.getMessage());
        }
    }

    protected void setVariable(String instanceId, String name, Object value, RestVariableScope scope, boolean isNew, boolean async, VariableInterceptor variableInterceptor) {
        if (isNew) {
            variableInterceptor.createVariables(Collections.singletonMap(name, value));
        } else {
            variableInterceptor.updateVariables(Collections.singletonMap(name, value));
        }

        if (RestVariableScope.LOCAL == scope) {
            //the guard is only added here, because this whole block is new
            if (isNew && runtimeService.hasLocalVariable(instanceId, name)) {
                throw new FlowableConflictException("Local variable '" + name + "' is already present on plan item instance '" + instanceId + "'.");
            }
            
            if (async) {
                runtimeService.setLocalVariableAsync(instanceId, name, value);
            } else {
                runtimeService.setLocalVariable(instanceId, name, value);
            }
            
        } else {
            if (async) {
                runtimeService.setVariableAsync(instanceId, name, value);
            } else {
                runtimeService.setVariable(instanceId, name, value);
            }
        }
    }

    protected VariableInterceptor createVariableInterceptor(PlanItemInstance planItemInstance) {

View on GitHub (pinned to d6d39ce1c6)