#7452·mem0

bug(memory): delete_all() leaves the scope's session messages, which are re-sent to the LLM on the next add()

Author: ac12644Created Sep 25, 2026Updated Sep 28, 2026
Labelssdk-python

Component

Python SDK

Description

Since the v3 pipeline (#4805), add() keeps the last 10 raw messages per session scope in the messages table of the history DB and feeds them back to the LLM as context on the next add().

delete_all() cleans up the scope's memories and its entity records, but never touches messages. There's also no way to clear one scope's messages at all: the only thing that deletes from that table is reset(), which drops it for every user.

So after delete_all(user_id="alice"), Alice's recent messages are still on disk, and her next add() sends them to the LLM again, where they can get re-extracted into new memories. For someone who asked to have their data removed, that's the part that matters.

Suggested fix: a small delete_messages(session_scope) on SQLiteManager, called from delete_all (sync and async), the same way delete_all already clears the scope's entity records. I left single-memory delete(memory_id) out on purpose, since messages aren't tied to one memory.

The TypeScript SDK looks to have the same gap (SQLiteManager.ts has saveMessages / getLastMessages but no scoped delete, and deleteAll doesn't touch messages), but I've only run the Python side.

How You Verified This

What I Ran

On main @ a39a802b, Python 3.12, fresh venv with pip install -e .. No API key needed, the LLM and embedder are stubbed and the history DB is a temp file:

python
import json, tempfile
from mem0 import Memory

d = tempfile.mkdtemp()
m = Memory.from_config({
    "llm": {"provider": "openai", "config": {"api_key": "unused"}},
    "embedder": {"provider": "openai", "config": {"api_key": "unused"}},
    "vector_store": {"provider": "qdrant", "config": {"path": f"{d}/q", "collection_name": "c", "embedding_model_dims": 8}},
    "history_db_path": f"{d}/history.db",
})
m.embedding_model.embed = lambda *a, **k: [0.1] * 8
m.embedding_model.embed_batch = lambda texts, *a, **k: [[0.1] * 8 for _ in texts]

prompts = []
def fake_llm(messages, **kwargs):
    prompts.append(messages[-1]["content"])
    return json.dumps({"memory": [{"id": "0", "text": "fact", "attributed_to": "user"}]})
m.llm.generate_response = fake_llm

m.add([{"role": "user", "content": "My SSN is 123-45-6789"}], user_id="alice")
m.delete_all(user_id="alice")
print(len(m.get_all(filters={"user_id": "alice"})["results"]))  # 0

m.add([{"role": "user", "content": "I like tea"}], user_id="alice")
print("123-45-6789" in prompts[-1])  # True
m.vector_store.client.close()

What I Saw

0
True

Memories are gone after delete_all, but the deleted message is back in the next extraction prompt.

Why This Is a Bug

delete_all already scrubs the entity records derived from the same messages, so the scope's data is clearly meant to go. Leaving the raw messages, with no per-scope way to remove them, means deleted content keeps being sent to the LLM provider and can come back as new memories.

What I Ruled Out

  • Not model-dependent: the repro stubs the LLM, so the result doesn't depend on what a model does.
  • Not a dup of #6915, which is about content ending up in logs.
  • The rolling window caps it at 10 messages per scope, so it's bounded, but those are the most recent ones.

AI Assistance

AI helped me find it, and I reproduced it myself afterwards