flowable/flowable-engine · error · FlowableIllegalArgumentException

Variable operation is missing for variable: ${name}

Error message

Variable operation is missing for variable: ${name}

What it means

PlanItemInstanceBaseResource.addVariables validates each QueryVariable in a plan-item-instance query: if variableOperation is null it throws FlowableIllegalArgumentException naming the variable. The plan item query API requires each variable filter to declare an operation (equals, notEquals, greaterThan, like, etc.) because the operation determines how the value is bound to the SQL comparison.

Source

Thrown at modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/runtime/planitem/PlanItemInstanceBaseResource.java:151

        if (queryRequest.getTenantId() != null) {
            query.planItemInstanceTenantId(queryRequest.getTenantId());
        }

        if (Boolean.TRUE.equals(queryRequest.getWithoutTenantId())) {
            query.planItemInstanceWithoutTenantId();
        }
        
        if (restApiInterceptor != null) {
            restApiInterceptor.accessPlanItemInstanceInfoWithQuery(query, queryRequest);
        }

        return paginateList(requestParams, queryRequest, query, "createTime", allowedSortProperties, restResponseFactory::createPlanItemInstanceResponseList);
    }

    protected void addVariables(PlanItemInstanceQuery planItemInstanceQuery, List<QueryVariable> variables, boolean isCase) {
        for (QueryVariable variable : variables) {
            if (variable.getVariableOperation() == null) {
                throw new FlowableIllegalArgumentException("Variable operation is missing for variable: " + variable.getName());
            }
            if (variable.getValue() == null) {
                throw new FlowableIllegalArgumentException("Variable value is missing for variable: " + variable.getName());
            }

            boolean nameLess = variable.getName() == null;

            Object actualValue = restResponseFactory.getVariableValue(variable);

            // A value-only query is only possible using equals-operator
            if (nameLess && variable.getVariableOperation() != QueryVariableOperation.EQUALS) {
                throw new FlowableIllegalArgumentException("Value-only query (without a variable-name) is only supported when using 'equals' operation.");
            }

            switch (variable.getVariableOperation()) {

            case EQUALS:
                if (nameLess) {

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Include the operation in the filter, e.g. ?variable=amount:equals:42 (name:operation:value).
  2. If using a JSON query request, set "operation":"equals" (or another supported op) on each variable entry.
  3. Fix client query-builder serialization so the operation field is never dropped.
  4. Check the allowed operation names in QueryVariable (equals, notEquals, greaterThan, greaterThanOrEquals, lessThan, lessThanOrEquals, like, notLike).

Example fix

// before
GET /cmmn-runtime/plan-item-instances?variable=amount,42
// after
GET /cmmn-runtime/plan-item-instances?variable=amount:equals:42
Defensive patterns

Strategy: validation

Validate before calling

for (const v of variableFilters) {
  if (!v.operation) throw new Error(`variable filter '${v.name}' missing operation (equals, greaterThan, like, ...)`);
}

Type guard

function hasOperation(v) { return v && typeof v.operation === 'string' && v.operation.length > 0; }

Try / catch

try { api.queryPlanItemInstances(query); }
catch (FlowableIllegalArgumentException e) { if (String(e.getMessage()).startsWith('Variable operation is missing')) { repairQueryOperations(e); } else throw e; }

Prevention

When it happens

Trigger: GET /cmmn-runtime/plan-item-instances?variable=amount,42 or a JSON query body omitting the 'operation' field for a variable filter; the operation key is misspelled or dropped by a client-side query builder.

Common situations: Query builders that serialize only name/value; hand-written URLs using the comma syntax where the operation segment was omitted; migration from another REST API where operations were implicit.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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