From b53507efd3b7cee41a0b74192a7eadb2f4b89b86 Mon Sep 17 00:00:00 2001 From: kartik-mem0 Date: Sat, 21 Mar 2026 18:04:10 +0530 Subject: [PATCH] fix(qdrant): reject mixed range and non-range filter operators Raise ValueError when a filter dict for a single field combines range operators (gt/gte/lt/lte) with non-range operators (eq/ne/in/nin/etc), preventing silent data loss where the non-range conditions were dropped. Co-Authored-By: Claude Sonnet 4.6 --- mem0/vector_stores/qdrant.py | 8 +++++++- tests/vector_stores/test_qdrant.py | 10 ++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/mem0/vector_stores/qdrant.py b/mem0/vector_stores/qdrant.py index d074a8923..47d29c5c8 100644 --- a/mem0/vector_stores/qdrant.py +++ b/mem0/vector_stores/qdrant.py @@ -161,9 +161,15 @@ class Qdrant(VectorStoreBase): ops = set(value.keys()) range_ops = {"gt", "gte", "lt", "lte"} + non_range_ops = ops - range_ops if ops & range_ops: - # Any combination of range operators: gt, gte, lt, lte + if non_range_ops: + raise ValueError( + f"Cannot mix range operators ({ops & range_ops}) with " + f"non-range operators ({non_range_ops}) for field '{key}'. " + f"Use AND to combine them as separate conditions." + ) range_kwargs = {op: value[op] for op in range_ops if op in value} return FieldCondition(key=key, range=Range(**range_kwargs)) elif "eq" in value: diff --git a/tests/vector_stores/test_qdrant.py b/tests/vector_stores/test_qdrant.py index 845167d7e..ca20a0eb5 100644 --- a/tests/vector_stores/test_qdrant.py +++ b/tests/vector_stores/test_qdrant.py @@ -541,5 +541,15 @@ class TestQdrantEnhancedFilters(unittest.TestCase): self.qdrant._build_field_condition("field", {"unknown_op": "foo"}) self.assertIn("Unsupported", str(ctx.exception)) + def test_mixed_range_and_non_range_raises_error(self): + """Mixing range ops with non-range ops should raise ValueError.""" + with self.assertRaises(ValueError): + self.qdrant._build_field_condition("priority", {"gte": 5, "ne": 10}) + + def test_mixed_range_and_eq_raises_error(self): + """Mixing range ops with eq should raise ValueError.""" + with self.assertRaises(ValueError): + self.qdrant._build_field_condition("score", {"gt": 0.5, "eq": 1.0}) + def tearDown(self): del self.qdrant