flowable/flowable-engine · error · FlowableIllegalArgumentException

Unsupported variable query operation:

Error message

Unsupported variable query operation: 

What it means

The switch over QueryVariableOperation in TaskBaseResource.addTaskvariables has a default branch that throws when the operation string does not map to any known enum constant handler. Practically this means the client supplied an unrecognized/unsupported variable operation name.

Solutions

  1. Use an exact QueryVariableOperation value: equals, notEquals, equalsIgnoreCase, notEqualsIgnoreCase, like, likeIgnoreCase, greaterThan, greaterThanOrEquals, lessThan, lessThanOrEquals, exists, notExists
  2. Check the Flowable version's QueryVariableOperation enum for supported names
  3. Fix typos in the query body

Example fix

// before
{"name":"x","operation":"contains","value":"abc"}
// after
{"name":"x","operation":"like","value":"%abc%"}
Defensive patterns

Strategy: validation

Validate before calling

const OPS = ['equals','notEquals','equalsIgnoreCase','notEqualsIgnoreCase','like','likeIgnoreCase','greaterThan','greaterThanOrEquals','lessThan','lessThanOrEquals','exists','notExists'];
function validateOp(v) {
  if (!OPS.includes(v.operation)) {
    throw new Error(`Unsupported variable operation: ${v.operation}`);
  }
}

Type guard

const isKnownOp = (op) => OPS.includes(op);

Try / catch

try {
  const res = await flowable.queryTasks(body);
} catch (e) {
  if (e.message && e.message.includes('Unsupported variable query operation')) {
    // correct the operation name against the server's Flowable version
  } else throw e;
}

Prevention

When it happens

Trigger: POST/GET /runtime/tasks with a taskVariables entry whose 'operation' is misspelled or not a valid QueryVariableOperation value (e.g. 'equal', 'contains'), or a newer operation sent to an older Flowable REST version.

Common situations: Typos in operation names; API version mismatch between client docs and server; copying operation names from a different engine (e.g. process-variable-only ops).

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at modules/flowable-rest/src/main/java/org/flowable/rest/service/api/runtime/task/TaskBaseResource.java:476

            case LIKE_IGNORE_CASE:
                if (actualValue instanceof String) {
                    taskQuery.taskVariableValueLikeIgnoreCase(variable.getName(), (String) actualValue);
                } else {
                    throw new FlowableIllegalArgumentException("Only string variable values are supported using like, but was: " + actualValue.getClass().getName());
                }
                break;

            case EXISTS:
                taskQuery.taskVariableExists(variable.getName());
                break;

            case NOT_EXISTS:
                taskQuery.taskVariableNotExists(variable.getName());
                break;

            default:
                throw new FlowableIllegalArgumentException("Unsupported variable query operation: " + variable.getVariableOperation());
            }
        }
    }

    protected void addProcessvariables(TaskQuery taskQuery, List<QueryVariable> variables) {
        for (QueryVariable variable : variables) {
            if (variable.getVariableOperation() == null) {
                throw new FlowableIllegalArgumentException("Variable operation is missing for variable: " + variable.getName());
            }
            if (variable.getVariableOperation() != QueryVariableOperation.EXISTS && variable.getVariableOperation() != QueryVariableOperation.NOT_EXISTS) {
                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);

View on GitHub (pinned to d6d39ce1c6)