{"record":{"id":"28782daa3f0557d6","repo":"spring-projects/spring-ai","slug":"expression-of-type-s-requires-a-right-operand","errorCode":null,"errorMessage":"Expression of type %s requires a right operand","messagePattern":"Expression of type (.+?) requires a right operand","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/SimpleVectorStoreFilterExpressionEvaluator.java","lineNumber":135,"sourceCode":"\t\t\t// A non-null right operand is silently ignored here.\n\t\t\tcase ISNULL -> metadataValue(left(expression), metadata) == null;\n\t\t\tcase ISNOTNULL -> metadataValue(left(expression), metadata) != null;\n\t\t};\n\t}\n\n\tprivate Filter.Operand left(Filter.Expression expression) {\n\t\tFilter.Operand left = expression.left();\n\t\tif (left == null) {\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\"Expression of type %s requires a left operand\".formatted(expression.type()));\n\t\t}\n\t\treturn left;\n\t}\n\n\tprivate Filter.Operand right(Filter.Expression expression) {\n\t\tFilter.Operand right = expression.right();\n\t\tif (right == null) {\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\"Expression of type %s requires a right operand\".formatted(expression.type()));\n\t\t}\n\t\treturn right;\n\t}\n\n\t/**\n\t * Extracts the metadata value for the given {@link Filter.Key} operand. Outer quotes\n\t * ({@code \"...\"} or {@code '...'}) are stripped from the key name to match the format\n\t * used by {@link FilterExpressionBuilder} and the text parser.\n\t */\n\tprivate @Nullable Object metadataValue(Filter.Operand operand, Map<String, Object> metadata) {\n\t\tif (operand instanceof Filter.Key key) {\n\t\t\tString k = key.key();\n\t\t\tif (k.length() >= 2\n\t\t\t\t\t&& ((k.startsWith(\"\\\"\") && k.endsWith(\"\\\"\")) || (k.startsWith(\"'\") && k.endsWith(\"'\")))) {\n\t\t\t\tk = k.substring(1, k.length() - 1);\n\t\t\t}\n\t\t\treturn metadata.get(k);","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/SimpleVectorStoreFilterExpressionEvaluator.java#L117-L153","documentation":"SimpleVectorStoreFilterExpressionEvaluator's right() helper unwraps the right operand of a Filter.Expression. If the right operand is null, it throws IllegalArgumentException naming the expression type. Binary filter expressions (EQ, IN, AND, OR, comparisons) all require a right operand.","triggerScenarios":"Passing a programmatically constructed Filter.Expression with null right operand into a SearchRequest filter, e.g. new Filter.Expression(GT, new Filter.Key(\"year\"), null).","commonSituations":"Manual Filter.Expression construction where the value operand was forgotten; deserialization dropping the right side; builder code with a conditional value path that returns null.","solutions":["Always supply a Filter.Value (or nested Filter.Expression) as the right operand when building Filter.Expression instances.","Use FilterExpressionTextParser to parse filter strings, which guarantees well-formed operands.","Null-check operands in any custom expression-building code before search."],"exampleFix":"// before\nnew Filter.Expression(Filter.ExpressionType.GT, new Filter.Key(\"year\"), null);\n// after\nnew Filter.Expression(Filter.ExpressionType.GT, new Filter.Key(\"year\"), new Filter.Value(2020));","handlingStrategy":"validation","validationCode":"boolean isWellFormed(Filter.Expression e) {\n    return e != null && e.left() != null && e.right() != null;\n}","typeGuard":"boolean hasRightOperand(Filter.Expression e) { return e != null && e.right() != null; }","tryCatchPattern":"try {\n    vectorStore.similaritySearch(request);\n} catch (IllegalArgumentException ex) {\n    if (ex.getMessage().contains(\"requires a right operand\")) {\n        // supply the missing Filter.Value and retry build\n    } else throw ex;\n}","preventionTips":["Always wrap literals in Filter.Value on the right side","Validate the full expression tree recursively before search"],"tags":["vector-store","filter-expression","missing-operand","spring-ai"],"backgroundTag":"missing-required-argument","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}