Skip to content

add() returns event: ADD for memories the vector store never persisted #6911

Closed

Description

@Aryan-Pillai7

Component

Python SDK

Description

Summary

When a batch insert into the vector store fails, _add_to_vector_store retries record-by-record. Records that also fail the retry are logged and skipped — but the returned payload, the history rows, and entity linking are all still built from the full extracted set. Callers receive {"id": ..., "event": "ADD"} for memories that were never stored, and get() on those ids later returns nothing.

Affects both Memory and AsyncMemory.

Steps to Reproduce

from mem0 import Memory

m = Memory()

# Simulate a store that rejects one record: batch insert fails,
# then one record also fails the per-record retry.
real_insert = m.vector_store.insert
POISON = "User is allergic to penicillin"

def flaky_insert(vectors, ids, payloads):
    if len(ids) > 1:
        raise RuntimeError("batch insert rejected")
    if payloads[0].get("data") == POISON:
        raise RuntimeError("record rejected by vector store")
    return real_insert(vectors=vectors, ids=ids, payloads=payloads)

m.vector_store.insert = flaky_insert

result = m.add(
    [{"role": "user", "content": f"My name is Aryan. {POISON}. I work as an engineer."}],
    user_id="u1",
)

for r in result["results"]:
    print(r["event"], r["id"], repr(r["memory"]), "| in store:", m.vector_store.get(r["id"]) is not None)

Expected Behavior

Only memories that actually persisted are returned as ADD. A record the store rejected should not appear in the results, should not get an ADD history row, and should not be referenced by linked_memory_ids in the entity store. If nothing persists at all, the call should raise VectorStoreError — which add()'s docstring already documents but nothing currently raises.

Actual Behavior

All three extracted memories are returned as successful ADDs while only two exist in the store. The failure surfaces only as a log line, at the same moment the call reports success.

ERROR mem0.memory.main: Failed to insert memory 330d01bf-...: record rejected by vector store

add() reported 3 memories as persisted:
  ADD c0196d4e "User's name is Aryan"             | in store: True
  ADD 330d01bf 'User is allergic to penicillin'   | in store: False   <-- phantom
  ADD 6d26dded 'User works as an engineer'        | in store: True

vector store actually holds 2 records

No exception is raised. The history table also gains an ADD row for the phantom id, and entity linked_memory_ids point at a memory that does not exist.

Source: mem0/memory/main.py — fallback loop at L1051 (sync) / L2704 (async); results built from the unfiltered records at L1190 / L2842.

Environment

  • mem0 version: 2.0.17
  • Python/Node version: Python 3.11
  • OS: Windows 11

Activity

  1. Diwak4r commented on Aug 22, 2026

    @Diwak4r
    Contributor

    Maintainer triage request (per the new PR-gate policy): I have a fix ready for this in #7066, and it will auto-reopen from the gate queue once this issue is labeled accepted.

    Quick summary of the approach so you can veto cheaply before reviewing:

    • Memory._add_to_vector_store / AsyncMemory._add_to_vector_store now track which records actually persisted (batch insert success = all persisted; on fallback, only records whose per-record insert succeeded).
    • Records the store rejected are excluded from the returned results, get no ADD history row, and are not referenced by entity linked_memory_ids.
    • If nothing persists at all, add() raises VectorStoreError — which the docstring already documented but nothing raised. Raw messages are still saved first so a retry can re-extract.

    One semantic choice worth confirming: on partial failure the call still succeeds and returns only the persisted records (rather than raising). If you would prefer partial failures to also raise, or to surface per-record status in the payload, I can adjust #7066 in a minute.

    4 regression tests included; full tests/memory/ suite (377 tests) and ruff are green.

  2. added
    acceptedA maintainer has agreed to this change. Required before a PR is reviewed.
    on Sep 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    acceptedA maintainer has agreed to this change. Required before a PR is reviewed.bugSomething isn't workingsdk-pythonPython SDK specific

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions