From 01afdde3e71781f1ae000e8d4c46c5912c0c13d4 Mon Sep 17 00:00:00 2001 From: Bartok Date: Fri, 24 Jul 2026 07:49:26 -0500 Subject: [PATCH] salvage: fix(opensearch) re-raise search errors (credit @yashwanth123 #6477) (#6519) Co-authored-by: yashwanth123 --- mem0/vector_stores/opensearch.py | 10 +++++++--- tests/vector_stores/test_opensearch.py | 21 ++++++++++++++++++--- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/mem0/vector_stores/opensearch.py b/mem0/vector_stores/opensearch.py index d041e9a65..73246858a 100644 --- a/mem0/vector_stores/opensearch.py +++ b/mem0/vector_stores/opensearch.py @@ -248,7 +248,7 @@ class OpenSearchDB(VectorStoreBase): return results except Exception as e: logger.error(f"Error during search: {e}", exc_info=True) - return [] + raise def keyword_search(self, query, top_k=5, filters=None): """Search for memories using BM25 keyword matching. @@ -293,8 +293,12 @@ class OpenSearchDB(VectorStoreBase): ] return results except Exception as e: - logger.error(f"Error during keyword search: {e}") - return [] + # Do NOT re-raise here: keyword_search() is a best-effort helper that + # search() may call to augment semantic results. Raising would crash + # the whole search() call on a keyword-only failure (regression per + # maintainer review on #6519). Log with exc_info and degrade to None. + logger.error(f"Error during keyword search: {e}", exc_info=True) + return None def delete(self, vector_id: str) -> None: """Delete a vector by custom ID.""" diff --git a/tests/vector_stores/test_opensearch.py b/tests/vector_stores/test_opensearch.py index ae413cf44..b9f481c29 100644 --- a/tests/vector_stores/test_opensearch.py +++ b/tests/vector_stores/test_opensearch.py @@ -424,10 +424,25 @@ class TestOpenSearchDB(unittest.TestCase): @patch("mem0.vector_stores.opensearch.logger") def test_search_error_logs_with_exc_info(self, mock_logger): - """Search error logging should include exc_info for full stack trace.""" + """Search errors should log with exc_info and re-raise (not swallow as []).""" self.client_mock.search.side_effect = Exception("Search failed") - results = self.os_db.search(query="", vectors=[[0.1] * 1536], top_k=5) - self.assertEqual(results, []) + with self.assertRaises(Exception): + self.os_db.search(query="", vectors=[[0.1] * 1536], top_k=5) + mock_logger.error.assert_called_once() + call_kwargs = mock_logger.error.call_args + self.assertTrue(call_kwargs[1].get("exc_info"), "logger.error must be called with exc_info=True") + + @patch("mem0.vector_stores.opensearch.logger") + def test_keyword_search_error_logs_and_degrades(self, mock_logger): + """Keyword search errors should log with exc_info and degrade to None (not raise). + + keyword_search() is a best-effort augmentation for search(); raising here + would crash the whole search() call on a keyword-only failure (regression + per maintainer review on #6519). + """ + self.client_mock.search.side_effect = Exception("Keyword search failed") + result = self.os_db.keyword_search(query="test", top_k=5) + self.assertIsNone(result) mock_logger.error.assert_called_once() call_kwargs = mock_logger.error.call_args self.assertTrue(call_kwargs[1].get("exc_info"), "logger.error must be called with exc_info=True")