{"record":{"id":"aa602d985f8b4fc6","repo":"flowable/flowable-engine","slug":"variable-operation-is-missing-for-variable-aa602d","errorCode":null,"errorMessage":"Variable operation is missing for variable: ","messagePattern":"Variable operation is missing for variable: ","errorType":"http","errorClass":"FlowableIllegalArgumentException","httpStatus":400,"severity":"error","filePath":"modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/history/variable/HistoricVariableInstanceBaseResource.java","lineNumber":119,"sourceCode":"    }\n    \n    public RestVariable getVariableFromRequest(boolean includeBinary, String varInstanceId) {\n        HistoricVariableInstance varObject = historyService.createHistoricVariableInstanceQuery().id(varInstanceId).singleResult();\n\n        if (varObject == null) {\n            throw new FlowableObjectNotFoundException(\"Historic variable instance '\" + varInstanceId + \"' couldn't be found.\", VariableInstanceEntity.class);\n        } else {\n            if (restApiInterceptor != null) {\n                restApiInterceptor.accessHistoryVariableInfoById(varObject);\n            }\n            return restResponseFactory.createRestVariable(varObject.getVariableName(), varObject.getValue(), null, varInstanceId, CmmnRestResponseFactory.VARIABLE_HISTORY_VARINSTANCE, includeBinary);\n        }\n    }\n\n    protected void addVariables(HistoricVariableInstanceQuery variableInstanceQuery, 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.getValue() == null) {\n                throw new FlowableIllegalArgumentException(\"Variable value is missing for variable: \" + variable.getName());\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\n            case EQUALS:\n                variableInstanceQuery.variableValueEquals(variable.getName(), actualValue);","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/history/variable/HistoricVariableInstanceBaseResource.java#L101-L137","documentation":"Thrown as FlowableIllegalArgumentException when a variable query predicate supplied to the historic variable instance query has no 'operation' field. The REST query endpoint accepts a variables filter array where each entry needs name, value, and operation (e.g. equals, like, greaterThan); operation is mandatory. Without it the query cannot know which operator to apply, so the request is rejected as invalid (HTTP 400).","triggerScenarios":"POST-style query GET /cmmn-history/historic-variable-instances?variables=... (or query body) with a variable entry like {\"name\":\"status\",\"value\":\"done\"} lacking \"operation\":\"equals\", or a client serializing QueryVariable objects with a null variableOperation.","commonSituations":"Hand-built query strings that omit the operation parameter, older client SDKs whose model predates the operation field, or JSON payloads where the operation key is misspelled (e.g. 'op') so it deserializes to null.","solutions":["Add the required operation to each variable filter, e.g. {\"name\":\"status\",\"value\":\"done\",\"operation\":\"equals\"}.","Use one of the supported operations: equals, notEquals, greaterThan, greaterThanOrEquals, lessThan, lessThanOrEquals, like, ignoreCaseEquals (per QueryVariable.QueryVariableOperation).","Fix JSON key spelling/casing so the operation field actually binds during deserialization.","Validate the query payload client-side before sending: every variable entry must have non-null name (or intentionally nameless) and operation."],"exampleFix":"// before: 400 - operation missing\n{\"variables\":[{\"name\":\"status\",\"value\":\"done\"}]}\n\n// after\n{\"variables\":[{\"name\":\"status\",\"value\":\"done\",\"operation\":\"equals\"}]}","handlingStrategy":"validation","validationCode":"if (variables.stream().anyMatch(v -> v.getOperation() == null)) {\n    throw new IllegalArgumentException(\"every variable filter needs an operation (equals, like, ...)\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    HistoricVariableInstanceListResponse r = query(variables);\n} catch (FlowableIllegalArgumentException e) {\n    // HTTP 400: invalid variable filter payload\n}","preventionTips":["Always include \"operation\" in variable filter entries","Use supported operations from QueryVariable.QueryVariableOperation","Check JSON key spelling so operation binds on deserialization","Test query payloads against the endpoint before wiring them into clients"],"tags":["rest-api","query","validation","flowable"],"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-14T05:17:10.506Z"}