{"record":{"id":"6101658320e7e3e1","repo":"spring-projects/spring-ai","slug":"unknown-expression-type","errorCode":null,"errorMessage":"Unknown expression type: ","messagePattern":"Unknown expression type: ","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/FilterHelper.java","lineNumber":98,"sourceCode":"\t\t\tswitch (exp.type()) {\n\t\t\t\tcase NOT: // NOT(NOT(a)) = a\n\t\t\t\t\treturn negate(exp.left());\n\t\t\t\tcase AND: // NOT(a AND b) = NOT(a) OR NOT(b)\n\t\t\t\tcase OR: // NOT(a OR b) = NOT(a) AND NOT(b)\n\t\t\t\t\treturn new Filter.Expression(TYPE_NEGATION_MAP.get(exp.type()), negate(exp.left()),\n\t\t\t\t\t\t\tnegate(exp.right()));\n\t\t\t\tcase EQ: // NOT(e EQ b) = e NE b\n\t\t\t\tcase NE: // NOT(e NE b) = e EQ b\n\t\t\t\tcase GT: // NOT(e GT b) = e LTE b\n\t\t\t\tcase GTE: // NOT(e GTE b) = e LT b\n\t\t\t\tcase LT: // NOT(e LT b) = e GTE b\n\t\t\t\tcase LTE: // NOT(e LTE b) = e GT b\n\t\t\t\t\treturn new Filter.Expression(TYPE_NEGATION_MAP.get(exp.type()), exp.left(), exp.right());\n\t\t\t\tcase IN: // NOT(e IN [...]) = e NIN [...]\n\t\t\t\tcase NIN: // NOT(e NIN [...]) = e IN [...]\n\t\t\t\t\treturn new Filter.Expression(TYPE_NEGATION_MAP.get(exp.type()), exp.left(), exp.right());\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new IllegalArgumentException(\"Unknown expression type: \" + exp.type());\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tthrow new IllegalArgumentException(\"Can not negate operand of type: \" + operand.getClass());\n\t\t}\n\t}\n\n\t/**\n\t * Expands the IN into a semantically equivalent boolean expressions of ORs of EQs.\n\t * Useful for providers that don't provide native IN support.\n\t *\n\t * For example the <pre>\n\t * foo IN [\"bar1\", \"bar2\", \"bar3\"]\n\t * </pre>\n\t *\n\t * expression is equivalent to\n\t *\n\t * <pre>","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/FilterHelper.java#L80-L116","documentation":"FilterHelper.negate computes the negation (NOT) of an expression by flipping its type via TYPE_NEGATION_MAP (GT<->LTE, EQ<->NE, IN<->NIN, etc.). If the expression's type has no entry in the map (e.g. AND/OR/NOT, or an unsupported type) it throws IllegalArgumentException(\"Unknown expression type: \" + type).","triggerScenarios":"Calling FilterHelper.negate() directly (or via inEx in expandIn/expandNin pipelines) with a Filter.Expression whose type() is not a simple comparison, such as NOT, AND, OR, or another type absent from TYPE_NEGATION_MAP.","commonSituations":"Custom vector-store code that reuses FilterHelper to push NOT down into provider-specific query languages; passing a compound expression where a leaf comparison was expected.","solutions":["Only pass leaf comparison expressions (EQ, NE, GT, GTE, LT, LTE, IN, NIN) to negate(); destructure AND/OR yourself and negate each branch","Handle NOT by dropping the outer NOT instead of calling negate on a NOT node (double negation)","Handle ISNULL/ISNOTNULL negation yourself before delegating to negate()","Catch IllegalArgumentException and fall back to emitting an explicit NOT(...) expression"],"exampleFix":"// before\nFilter.Expression n = FilterHelper.negate(andExpr); // throws\n// after\nFilter.Expression n = new Filter.Expression(ExpressionType.NOT, andExpr); // or negate each leaf","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"boolean isNegatable(Filter.Expression e) { return Set.of(ExpressionType.EQ, ExpressionType.NE, ExpressionType.GT, ExpressionType.GTE, ExpressionType.LT, ExpressionType.LTE, ExpressionType.IN, ExpressionType.NIN).contains(e.type()); }","tryCatchPattern":"try { return FilterHelper.negate(exp); }\ncatch (IllegalArgumentException e) { return new Filter.Expression(ExpressionType.NOT, exp); }","preventionTips":["Only negate leaf comparison expressions","Push NOT through AND/OR yourself (De Morgan) before negating leaves"],"tags":["filter-expression","negation","vector-store"],"backgroundTag":"unsupported-operation","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}