{"record":{"id":"e6f83acf6c3b8c15","repo":"flowable/flowable-engine","slug":"booleans-and-null-cannot-be-used-in-less-than-co","errorCode":null,"errorMessage":"Booleans and null cannot be used in 'less than' condition","messagePattern":"Booleans and null cannot be used in 'less than' condition","errorType":"validation","errorClass":"FlowableIllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/AbstractVariableQueryImpl.java","lineNumber":309,"sourceCode":"        addVariable(name, null, QueryOperator.NOT_EXISTS, scopeType, false);\n        return (T) this;\n    }\n\n    protected void addVariable(String name, Object value, QueryOperator operator, boolean localScope) {\n        this.addVariable(name, value, operator, null, localScope);\n    }\n\n    protected void addVariable(String name, Object value, QueryOperator operator, String scopeType, boolean localScope) {\n        if (name == null) {\n            throw new FlowableIllegalArgumentException(\"name is null\");\n        }\n        if (value == null || isBoolean(value)) {\n            // Null-values and booleans can only be used in EQUALS, NOT_EQUALS, EXISTS and NOT_EXISTS\n            switch (operator) {\n                case GREATER_THAN:\n                    throw new FlowableIllegalArgumentException(\"Booleans and null cannot be used in 'greater than' condition\");\n                case LESS_THAN:\n                    throw new FlowableIllegalArgumentException(\"Booleans and null cannot be used in 'less than' condition\");\n                case GREATER_THAN_OR_EQUAL:\n                    throw new FlowableIllegalArgumentException(\"Booleans and null cannot be used in 'greater than or equal' condition\");\n                case LESS_THAN_OR_EQUAL:\n                    throw new FlowableIllegalArgumentException(\"Booleans and null cannot be used in 'less than or equal' condition\");\n                default:\n                    break;\n            }\n\n            if (operator == QueryOperator.EQUALS_IGNORE_CASE && !(value instanceof String)) {\n                throw new FlowableIllegalArgumentException(\"Only string values can be used with 'equals ignore case' condition\");\n            }\n\n            if (operator == QueryOperator.NOT_EQUALS_IGNORE_CASE && !(value instanceof String)) {\n                throw new FlowableIllegalArgumentException(\"Only string values can be used with 'not equals ignore case' condition\");\n            }\n\n            if ((operator == QueryOperator.LIKE || operator == QueryOperator.LIKE_IGNORE_CASE) && !(value instanceof String)) {\n                throw new FlowableIllegalArgumentException(\"Only string values can be used with 'like' condition\");","sourceCodeStart":291,"sourceCodeEnd":327,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-variable-service/src/main/java/org/flowable/variable/service/impl/AbstractVariableQueryImpl.java#L291-L327","documentation":"Flowable variable queries reject null and Boolean values for the LESS_THAN operator since neither has a defined ordering in variable SQL comparisons. The guard is in AbstractVariableQueryImpl.addVariable and throws FlowableIllegalArgumentException immediately when the query clause is added. This is fail-fast API validation, not a runtime/database failure.","triggerScenarios":"Calling variableValueLessThan-style setters (routed through addVariable) with a null value or a Boolean, e.g. processVariableValueLessThan(\"enabled\", false).","commonSituations":"Using a boolean flag as if it were comparable; nulls flowing from optional config into query builders; generic query-building code that forwards any Object as a comparison value.","solutions":["Replace LESS_THAN with EQUALS/NOT_EQUALS or EXISTS/NOT_EXISTS for null/boolean values","Re-model the variable as a numeric or date type to allow ordering","Validate the value before building the clause and skip or translate the condition","Apply the comparison in application code after a broader query"],"exampleFix":"// before\nquery.variableValueLessThan(\"completed\", null);\n// after\nquery.variableValueEquals(\"completed\", false); // or variableValueExists(\"completed\")","handlingStrategy":"validation","validationCode":"if (value == null || value instanceof Boolean) {\n    throw new IllegalArgumentException(\"Use equals/exists operators for null or boolean variable values\");\n}\nquery.variableValueLessThan(name, value);","typeGuard":"static boolean supportsOrdering(Object v) {\n    return v instanceof Number || v instanceof Date || v instanceof String;\n}","tryCatchPattern":"try {\n    query.variableValueLessThan(name, value);\n} catch (org.flowable.common.engine.api.FlowableIllegalArgumentException e) {\n    // degrade to equals or drop the clause\n}","preventionTips":["Check the value type before using less-than comparisons","Translate boolean conditions to equals clauses","Avoid forwarding raw Objects from generic maps into query builders","Cover query building with unit tests for null/boolean inputs"],"tags":["flowable","validation","query","boolean"],"backgroundTag":"invalid-argument-value","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-18T11:17:12.947Z"}