Repository navigation
fix(memory): re-raise LLM extraction failures instead of returning [] (salvage of #5178) - #5878
Conversation
Changes RequestedReally solid salvage — the root diagnosis is exactly right and the PR description is the clearest explanation of this bug I've seen. Two things need to land before this merges. Strengths
IssuesImportant (should fix before merge)1.
@pytest.mark.asyncio
async def test_async_llm_extraction_exception_is_reraised(self, mocker, mock_async_memory):
class _ProviderError(Exception):
pass
mock_async_memory.llm.generate_response.side_effect = _ProviderError("429 rate limit")
mocker.patch("mem0.memory.main.capture_event")
with pytest.raises(_ProviderError):
await mock_async_memory._add_to_vector_store(
messages=[{"role": "user", "content": "test"}], metadata={}, filters={}, infer=True
)2.
Note: this docstring was a dead letter pre-PR too ( Minor (optional)
Evidence
AssessmentReady to merge: With fixes — please add the async test and resolve the For tracking on our side, mind opening a short issue describing this bug and linking it here? Makes it easier to reference and prioritize follow-ups like the TS side. |
…ression test Address review on mem0ai#5878: - Honour the documented LLMError contract: both sync and async _add_to_vector_store now raise LLMError (chained via 'from e' to the original provider exception) instead of a bare re-raise, so callers using 'except LLMError' per the docstring actually catch it. - Add TestAsyncAddToVectorStoreErrors.test_async_llm_extraction_exception_is_reraised so a revert of the async raise back to 'return []' can no longer pass the suite silently.
This comment was marked as spam.
This comment was marked as spam.
This comment was marked as spam.
This comment was marked as spam.
LGTM — re-review complete, ready for squash-mergeBoth items from the prior review are fully addressed. What changed in the follow-up commit
Strengths
IssuesImportant (for tracking, not a merge blocker here): The TS SDK has the identical silent-swallow at Minor: The async test patches Evidence
AssessmentReady to merge: Yes (squash) · Est. human time: ~3 min The fix is at the right layer, fulfils the pre-existing documented contract, both sync and async paths are tested with a tight red-green proof, and the exception chain is preserved for callers who need to inspect the original error. Please make sure #5903 gets a TS-side fix PR queued as a follow-up. Also: once this merges, PR #5178 (the original by the credited author) has merge conflicts and no regression test — it can be closed. |
Salvage of #5178 by @thalesfsp — rebased onto current main with a regression guardrail test added.
Summary
Re-raise provider errors during fact extraction instead of swallowing them and returning
[].Root Cause
Symptom — When the LLM call in
_add_to_vector_storefails (HTTP 429, 5xx, connection error, timeout),add()silently returns an empty result. Callers cannot tell "LLM was unavailable" from "LLM ran fine and extracted no facts" — both look like[].Root cause — Both the sync
Memory._add_to_vector_storeand asyncAsyncMemory._add_to_vector_storewrapself.llm.generate_response(...)in a bareexcept Exceptionthat logs andreturn []. The exception is destroyed at the point it occurs, so no signal reaches the caller.Evidence —
mem0/memory/main.py: the sync path (logger.error("LLM extraction failed: {e}"); return []) and the async path (... (async): {e}"); return []). Confirmed present on currentmain(0fbbb2f). The new regression test below fails on unmodified main (the call returns[], no exception) and passes with the fix.Fix + why this level — Replace
return []withraisein both extraction error handlers, keeping the existinglogger.error. This is the correct layer: extraction is where provider transport errors first surface, and re-raising lets any wrapping retry/fallback layer (e.g. a multi-provider failover) distinguish transport failure from an empty extraction. Patching a downstream caller can't recover information already discarded here. Parse errors further down still return[](that genuinely means "no usable facts"), so only true provider exceptions propagate.Scope / risk — Touches only the two extraction
exceptblocks. Behavior change: anadd()that previously returned[]on a provider outage now raises. This is the intended, documented contract change; callers relying on the silent-swallow behavior should wrap in try/except. Parse-error and empty-response handling is unchanged.Why it needed salvage
The original #5178 was conflicting against current main after pipeline refactors. Re-applied cleanly onto current
mainand added a guardrail test the original lacked.Changes from original
main(single clean commit, authorship credited).test_llm_extraction_exception_is_reraised— asserts a provider error propagates; fails without the fix (returns[]), passes with it.Verification / Real behavior proof
ruff checkclean. Fulltests/memory/test_main.pysuite (46 tests) passes.Credit: salvage of #5178 by @thalesfsp.