{"record":{"id":"f3c10fbb43c68677","repo":"spring-projects/spring-ai","slug":"expected-value-but-got","errorCode":null,"errorMessage":"Expected Value but got: ","messagePattern":"Expected Value but got: ","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"vector-stores/spring-ai-bedrock-knowledgebase-store/src/main/java/org/springframework/ai/vectorstore/bedrockknowledgebase/BedrockKnowledgeBaseFilterExpressionConverter.java","lineNumber":147,"sourceCode":"\t\treturn RetrievalFilter.builder().notIn(attr).build();\n\t}\n\n\tprivate FilterAttribute createFilterAttribute(final String key, final Object value) {\n\t\treturn FilterAttribute.builder().key(key).value(toDocument(value)).build();\n\t}\n\n\tprivate Expression asExpression(final Filter.Operand operand) {\n\t\tif (operand instanceof Expression expr) {\n\t\t\treturn expr;\n\t\t}\n\t\tthrow new IllegalArgumentException(\"Expected Expression but got: \" + operand.getClass());\n\t}\n\n\tprivate Object extractValue(final Filter.Operand operand) {\n\t\tif (operand instanceof Value value) {\n\t\t\treturn value.value();\n\t\t}\n\t\tthrow new IllegalArgumentException(\"Expected Value but got: \" + operand.getClass());\n\t}\n\n\tprivate List<?> extractListValue(final Filter.Operand operand) {\n\t\tObject value = extractValue(operand);\n\t\tif (value instanceof List) {\n\t\t\treturn (List<?>) value;\n\t\t}\n\t\tthrow new IllegalArgumentException(\"Expected List for IN/NIN but got: \" + value.getClass());\n\t}\n\n\tprivate Document toDocument(final Object value) {\n\t\tif (value instanceof String s) {\n\t\t\treturn Document.fromString(s);\n\t\t}\n\t\tif (value instanceof Number n) {\n\t\t\treturn Document.fromNumber(n.toString());\n\t\t}\n\t\tif (value instanceof Boolean b) {","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/vector-stores/spring-ai-bedrock-knowledgebase-store/src/main/java/org/springframework/ai/vectorstore/bedrockknowledgebase/BedrockKnowledgeBaseFilterExpressionConverter.java#L129-L165","documentation":"extractValue narrows a Filter.Operand to a Filter.Value and returns its raw Java value when building comparison operands for Bedrock RetrievalFilter documents. If the operand is an Expression rather than a Value (a key or sub-expression on the value side of a comparison), it throws an IllegalArgumentException naming the actual class.","triggerScenarios":"Building a comparison like GT(expr, expr) or EQ(key, anotherKey) where the right-hand side is an Expression instead of a literal Value, then converting via BedrockKnowledgeBaseFilterExpressionConverter or running similaritySearch with that filterExpression.","commonSituations":"Programmatic filter builders that put field references on the value side (field-to-field comparisons); copy-pasted filter code from stores that support key-to-key comparison; confusion between ExpressionText-as-key and value operand roles.","solutions":["Always place a literal (Filter.Value) on the value side of comparisons; compare against constants, not other fields","If field-to-field comparison is needed, compute it differently (e.g. filter client-side) since Bedrock converter only supports literal comparisons","Validate the tree before conversion: right operand must be instanceof Filter.Value","Catch IllegalArgumentException and surface which comparison operand had the wrong type"],"exampleFix":"// before\nExpression e = GT(new ExpressionText(\"price\"), new ExpressionText(\"msrp\")); // value side is an Expression\n// after\nExpression e = GT(new ExpressionText(\"price\"), 99.99); // literal Value on the right","handlingStrategy":"type-guard","validationCode":"if (expr.left() != null && expr.right() != null && !(expr.right() instanceof Value)) { throw new IllegalArgumentException(\"Comparison value side must be a literal Value\"); }","typeGuard":"Object requireLiteral(Filter.Operand o) { if (o instanceof Value v) return v.value(); throw new IllegalArgumentException(\"Expected literal value operand, got: \" + o.getClass()); }","tryCatchPattern":"try { String filter = converter.convertExpression(expression); ... } catch (IllegalArgumentException e) { log.error(\"Comparison value must be literal: {}\", e.getMessage()); /* rebuild filter with literals */ }","preventionTips":["Never compare field-to-field; compare against constants","Keep keys on the left, literals on the right in comparisons","Validate comparison operands before conversion","Cover all comparison filters in unit tests for Bedrock KB"],"tags":["bedrock","filter-expression","type-mismatch","aws"],"backgroundTag":"type-mismatch","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"}