{"record":{"id":"f603bfd5ac31d48e","repo":"spring-projects/spring-ai","slug":"expression-of-type-s-requires-a-right-operand-f603bf","errorCode":null,"errorMessage":"Expression of type %s requires a right operand","messagePattern":"Expression of type (.+?) requires a right operand","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"vector-stores/spring-ai-s3-vector-store/src/main/java/org/springframework/ai/vectorstore/s3/S3VectorStoreFilterExpressionEvaluator.java","lineNumber":93,"sourceCode":"\t\t\t}\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\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);\n\t\t}\n\t\tthrow new IllegalArgumentException(\"Expected a Key operand but got: \" + operand.getClass().getName());\n\t}\n\n\tprivate Object filterValue(Filter.Operand operand) {","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/vector-stores/spring-ai-s3-vector-store/src/main/java/org/springframework/ai/vectorstore/s3/S3VectorStoreFilterExpressionEvaluator.java#L75-L111","documentation":"The evaluator's right() accessor throws IllegalArgumentException when a Filter.Expression lacks a right operand where one is required. Binary operators (AND, OR, EQ, NE, GT, GTE, LT, LTE, IN, NIN) all dereference right(), so a null right operand is rejected as a malformed filter.","triggerScenarios":"Building a comparison like new Filter.Expression(EQ, new Filter.Key(\"genre\"), null) or a binary AND/OR missing its second child, then running S3VectorStore similaritySearch that evaluates the filter against ListVectors metadata.","commonSituations":"Partial filter assembly (value forgotten); ISNULL/ISNOTNULL-style expressions ported from other stores where the right side is null by convention — here ISNULL/ISNOTNULL read only the left side, but comparisons with null right side throw; dynamic filter builders that skip unset values.","solutions":["Always supply a Filter.Value for comparison operators; use the string \"null\" sentinel or a dedicated metadata flag if you mean 'missing'.","For null checks use ISNULL/ISNOTNULL expression types, which do not require a right operand.","Skip building the expression entirely when the value is absent, rather than passing null.","Validate the filter tree (all binary nodes have both operands) before calling similaritySearch."],"exampleFix":"// before\nnew Filter.Expression(Filter.ExpressionType.EQ, new Filter.Key(\"genre\"), null)\n// after\nnew Filter.Expression(Filter.ExpressionType.ISNULL, new Filter.Key(\"genre\"), null)","handlingStrategy":"validation","validationCode":"static boolean needsRight(Filter.ExpressionType t) { return t != NOT && t != ISNULL && t != ISNOTNULL; }\nstatic void requireRight(Filter.Expression e) { if (needsRight(e.type()) && e.right() == null) throw new IllegalStateException(\"Missing right operand\"); }","typeGuard":"static boolean hasRight(Filter.Expression e) { return e.right() != null; }","tryCatchPattern":"try { store.similaritySearch(req); } catch (IllegalArgumentException e) { if (e.getMessage().endsWith(\"requires a right operand\")) { /* drop or rebuild the incomplete predicate */ } }","preventionTips":["Skip building predicates whose value is null; use ISNULL/ISNOTNULL for missing-field checks.","Guard dynamic filter builders: never pass null as a right operand for binary operators.","Validate the complete filter tree before similaritySearch."],"tags":["vector-store","filter-expression","null-operand","post-filtering","aws-s3-vectors"],"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-14T11:17:12.474Z"}