{"record":{"id":"bb0e4a884c799ba0","repo":"flowable/flowable-engine","slug":"variable-operation-is-missing-for-variable-vari-bb0e4a","errorCode":null,"errorMessage":"Variable operation is missing for variable: ${variable.getName()}","messagePattern":"Variable operation is missing for variable: (.+?)","errorType":"validation","errorClass":"FlowableIllegalArgumentException","httpStatus":400,"severity":"error","filePath":"modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/history/task/HistoricTaskInstanceBaseResource.java","lineNumber":325,"sourceCode":"    }\n\n    /**\n     * Returns the {@link HistoricTaskInstance} that is requested without calling the access interceptor\n     * Throws the right exceptions when bad request was made or instance was not found.\n     */\n    protected HistoricTaskInstance getHistoricTaskInstanceFromRequestWithoutAccessCheck(String taskId) {\n        HistoricTaskInstance taskInstance = historyService.createHistoricTaskInstanceQuery().taskId(taskId).singleResult();\n        if (taskInstance == null) {\n            throw new FlowableObjectNotFoundException(\"Could not find a task instance with id '\" + taskId + \"'.\", HistoricTaskInstance.class);\n        }\n        \n        return taskInstance;\n    }\n\n    protected void addTaskVariables(HistoricTaskInstanceQuery taskInstanceQuery, List<QueryVariable> variables) {\n        for (QueryVariable variable : variables) {\n            if (variable.getVariableOperation() == null) {\n                throw new FlowableIllegalArgumentException(\"Variable operation is missing for variable: \" + variable.getName());\n            }\n            if (variable.getVariableOperation() != QueryVariableOperation.EXISTS && variable.getVariableOperation() != QueryVariableOperation.NOT_EXISTS) {\n                if (variable.getValue() == null) {\n                    throw new FlowableIllegalArgumentException(\"Variable value is missing for variable: \" + variable.getName());\n                }\n            }\n\n            boolean nameLess = variable.getName() == null;\n\n            Object actualValue = restResponseFactory.getVariableValue(variable);\n\n            // A value-only query is only possible using equals-operator\n            if (nameLess) {\n                throw new FlowableIllegalArgumentException(\"Value-only query (without a variable-name) is not supported.\");\n            }\n\n            switch (variable.getVariableOperation()) {\n","sourceCodeStart":307,"sourceCodeEnd":343,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/history/task/HistoricTaskInstanceBaseResource.java#L307-L343","documentation":"FlowableIllegalArgumentException thrown while building a historic task instance query when a supplied query variable has no variableOperation set. The REST variable query parameter requires an explicit operation (equals, greaterThan, exists, etc.); an operation-less variable is an invalid request body. This is a client request validation error (HTTP 400).","triggerScenarios":"POST /cmmn-history/historic-task-instances/query (variable handling inside getQueryResponse) with a body like {\"taskVariableValues\":[{\"name\":\"priority\"}]} - the variable object omits the 'operation' field.","commonSituations":"Hand-written JSON query bodies missing the operation key; client DTO serialization dropping the operation field; upgrading clients against older API shapes that defaulted operations.","solutions":["Add the required 'operation' field to each variable object in the query body (e.g. \"operation\":\"equals\").","Use one of the supported QueryVariableOperation values: EQUALS, NOT_EQUALS, EQUALS_IGNORE_CASE, NOT_EQUALS_IGNORE_CASE, GREATER_THAN, GREATER_THAN_OR_EQUAL, LESS_THAN, LESS_THAN_OR_EQUAL, LIKE, EXISTS, NOT_EXISTS, etc.","Validate the request payload client-side before sending; reject variables without an operation.","Check client serialization is not omitting the operation due to null/naming mismatch."],"exampleFix":"// before\n{\"taskVariableValues\":[{\"name\":\"priority\",\"value\":1}]}\n// after\n{\"taskVariableValues\":[{\"name\":\"priority\",\"value\":1,\"operation\":\"EQUALS\"}]}","handlingStrategy":"validation","validationCode":"function validateQueryVars(vars) {\n  for (const v of vars.taskVariableValues || []) {\n    if (!v.operation) throw new Error(\"variable '\" + v.name + \"' is missing 'operation'\");\n  }\n}","typeGuard":"const hasOperation = (v) => typeof v.operation === 'string' && v.operation.length > 0;","tryCatchPattern":null,"preventionTips":["Include 'operation' in every variable query condition.","Use the exact enum literal (e.g. EQUALS) accepted by QueryVariableOperation.","Add schema validation (JSON Schema/OpenAPI) on request bodies.","Test query payloads against the API before shipping clients."],"tags":["flowable","rest","validation","query"],"backgroundTag":"missing-required-argument","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}