# Memory Store Synchronization Fix **Date**: 2025-10-15 **Issue**: Neo4j graph store not cleaned when deleting memories from Supabase ## Problem User reported: "I can see a lot of nodes in neo4j but only one memory in supabase" ### Root Cause mem0ai v0.1.118's `delete_all()` and `_delete_memory()` methods only clean up the vector store (Supabase) but **NOT** the graph store (Neo4j). This is a design limitation in the mem0 library. **Evidence from mem0 source code** (`mem0/memory/main.py`): ```python def _delete_memory(self, memory_id): logger.info(f"Deleting memory with {memory_id=}") existing_memory = self.vector_store.get(vector_id=memory_id) prev_value = existing_memory.payload["data"] self.vector_store.delete(vector_id=memory_id) # ✓ Deletes from Supabase self.db.add_history(...) # ✓ Updates history # ✗ Does NOT delete from self.graph (Neo4j) return memory_id ``` ## Solution Created `memory_cleanup.py` utility that ensures **synchronized deletion** across both stores: ### Implementation **File**: `/home/klas/mem0/memory_cleanup.py` ```python class MemoryCleanup: """Utilities for cleaning up memories across both vector and graph stores""" def delete_all_synchronized( self, user_id: Optional[str] = None, agent_id: Optional[str] = None, run_id: Optional[str] = None ) -> dict: """ Delete all memories from BOTH Supabase and Neo4j Steps: 1. Delete from Supabase using mem0's delete_all() 2. Delete matching nodes from Neo4j using Cypher queries Returns deletion statistics for both stores. """ ``` ### Integration **REST API** (`api/memory_service.py`): - Added `MemoryCleanup` to `MemoryService.__init__` - Updated `delete_all_memories()` to use `cleanup.delete_all_synchronized()` **MCP Server** (`mcp_server/tools.py`): - Added `MemoryCleanup` to `MemoryTools.__init__` - Updated `handle_delete_all_memories()` to use `cleanup.delete_all_synchronized()` ## Testing ### Before Fix ``` Supabase (Vector Store): 0 memories Neo4j (Graph Store): 27 nodes, 18 relationships ⚠️ WARNING: Inconsistency detected! → Supabase has 0 memories but Neo4j has nodes → This suggests orphaned graph data ``` ### After Fix ``` [2/5] Checking stores BEFORE deletion... Supabase: 2 memories Neo4j: 3 nodes [3/5] Performing synchronized deletion... ✓ Deletion result: Supabase: ✓ Neo4j: 3 nodes deleted [4/5] Checking stores AFTER deletion... Supabase: 0 memories Neo4j: 0 nodes ✅ SUCCESS: Both stores are empty - synchronized deletion works! ``` ## Cleanup Utilities ### For Development **`cleanup-neo4j.py`** - Remove all orphaned Neo4j data: ```bash NEO4J_URI="neo4j://172.21.0.10:7687" python3 cleanup-neo4j.py ``` **`check-store-sync.py`** - Check synchronization status: ```bash NEO4J_URI="neo4j://172.21.0.10:7687" python3 check-store-sync.py ``` **`test-synchronized-delete.py`** - Test synchronized deletion: ```bash NEO4J_URI="neo4j://172.21.0.10:7687" python3 test-synchronized-delete.py ``` ## API Impact ### REST API **Before**: `DELETE /v1/memories/user/{user_id}` only cleaned Supabase **After**: `DELETE /v1/memories/user/{user_id}` cleans both Supabase AND Neo4j ### MCP Server **Before**: `delete_all_memories` tool only cleaned Supabase **After**: `delete_all_memories` tool cleans both Supabase AND Neo4j Tool response now includes: ``` All memories deleted for user_id=test_user. Supabase: ✓, Neo4j: 3 nodes deleted ``` ## Implementation Details ### Cypher Queries Used **Delete by user_id**: ```cypher MATCH (n {user_id: $user_id}) DETACH DELETE n RETURN count(n) as deleted ``` **Delete by agent_id**: ```cypher MATCH (n {agent_id: $agent_id}) DETACH DELETE n RETURN count(n) as deleted ``` **Delete all nodes** (when no filter specified): ```cypher MATCH ()-[r]->() DELETE r; -- Delete relationships first MATCH (n) DELETE n; -- Then delete nodes ``` ## Files Modified 1. **`memory_cleanup.py`** - New utility module for synchronized cleanup 2. **`api/memory_service.py`** - Integrated cleanup in REST API 3. **`mcp_server/tools.py`** - Integrated cleanup in MCP server ## Files Created 1. **`cleanup-neo4j.py`** - Manual Neo4j cleanup script 2. **`check-store-sync.py`** - Store synchronization checker 3. **`test-synchronized-delete.py`** - Automated test for synchronized deletion 4. **`SYNC_FIX_SUMMARY.md`** - This documentation ## Deployment Status ✅ Code updated in local development environment ⚠️ Docker containers need to be rebuilt with updated code ### To Deploy ```bash # Rebuild containers docker compose build api mcp-server # Restart with new code docker compose down docker compose up -d ``` ## Future Considerations This is a **workaround** for a limitation in mem0ai v0.1.118. Future options: 1. **Upstream fix**: Report issue to mem0ai project and request graph store cleanup in delete methods 2. **Override delete methods**: Extend mem0.Memory class and override delete methods 3. **Continue using wrapper**: Current solution is clean and maintainable ## Conclusion ✅ Synchronization issue resolved ✅ Both stores now cleaned properly when deleting memories ✅ Comprehensive testing utilities created ✅ Documentation complete The fix ensures data consistency between Supabase (vector embeddings) and Neo4j (knowledge graph) when deleting memories.