What happens
Measured on main at ad8ff24: one upsert call with two records of the same UUID, the first with properties {"a": 1} and vector [1, 0, 0], the second with {"a": 2} and vector [0, 1, 0].
| store |
result |
SQLiteVectorStore |
one record, the second one's properties and vector |
QdrantVectorStore (Qdrant 1.17.0, REST and gRPC) |
one record, the second one's properties and vector |
MilvusVectorStore on Milvus Lite 3.2.1 |
one record, the second one's properties and vector |
SQLiteVecVectorStore |
raises sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) UNIQUE constraint failed on vector_store_sqlite_vec_…_vc primary key |
MilvusVectorStore on Milvus 2.6.24 |
raises MilvusException: (code=1100, message=duplicate primary keys are not allowed in the same batch: invalid parameter) |
Why
SQLiteVectorStore writes the records table with one INSERT ... ON CONFLICT (uuid) DO UPDATE over the batch, so the second row updates the first, and keys the search engine's vectors by row id, so the second vector replaces the first (packages/server/src/memmachine_server/common/vector_store/sqlite_vector_store.py:286-311, :346-350).
SQLiteVecVectorStore writes the records table the same way, then deletes and inserts each record's row of the vec0 table by row id (packages/server/src/memmachine_server/common/vector_store/sqlite_vec_vector_store.py:144-190); the second insert of the same row id violates the vec0 primary key, and the driver's error reaches the caller unchanged.
QdrantVectorStore sends one point per record (packages/server/src/memmachine_server/common/vector_store/qdrant_vector_store.py:293-315), and Qdrant keeps the last.
MilvusVectorStore sends one entity per record under the primary key <partition key>:<uuid> (packages/server/src/memmachine_server/common/vector_store/milvus_vector_store.py:151-153, :254-273). Milvus 2.6.24 refuses a batch that repeats a primary key; Milvus Lite keeps the last.
Expected
Every store answers such a batch the same way: it refuses the batch with one error type, before writing anything.
Fix
A fix is in progress on feat/horizontal-scaling: the stores refuse a batch that repeats a record UUID.
🤖 Written by Claude Code (Claude Opus 5.5) on behalf of @edwinyyyu.
What happens
Measured on
mainat ad8ff24: oneupsertcall with two records of the same UUID, the first with properties{"a": 1}and vector[1, 0, 0], the second with{"a": 2}and vector[0, 1, 0].SQLiteVectorStoreQdrantVectorStore(Qdrant 1.17.0, REST and gRPC)MilvusVectorStoreon Milvus Lite 3.2.1SQLiteVecVectorStoresqlalchemy.exc.OperationalError: (sqlite3.OperationalError) UNIQUE constraint failed on vector_store_sqlite_vec_…_vc primary keyMilvusVectorStoreon Milvus 2.6.24MilvusException: (code=1100, message=duplicate primary keys are not allowed in the same batch: invalid parameter)Why
SQLiteVectorStorewrites the records table with oneINSERT ... ON CONFLICT (uuid) DO UPDATEover the batch, so the second row updates the first, and keys the search engine's vectors by row id, so the second vector replaces the first (packages/server/src/memmachine_server/common/vector_store/sqlite_vector_store.py:286-311,:346-350).SQLiteVecVectorStorewrites the records table the same way, then deletes and inserts each record's row of thevec0table by row id (packages/server/src/memmachine_server/common/vector_store/sqlite_vec_vector_store.py:144-190); the second insert of the same row id violates thevec0primary key, and the driver's error reaches the caller unchanged.QdrantVectorStoresends one point per record (packages/server/src/memmachine_server/common/vector_store/qdrant_vector_store.py:293-315), and Qdrant keeps the last.MilvusVectorStoresends one entity per record under the primary key<partition key>:<uuid>(packages/server/src/memmachine_server/common/vector_store/milvus_vector_store.py:151-153,:254-273). Milvus 2.6.24 refuses a batch that repeats a primary key; Milvus Lite keeps the last.Expected
Every store answers such a batch the same way: it refuses the batch with one error type, before writing anything.
Fix
A fix is in progress on
feat/horizontal-scaling: the stores refuse a batch that repeats a record UUID.🤖 Written by Claude Code (Claude Opus 5.5) on behalf of @edwinyyyu.