fix(vector_stores): handle vector=None in Milvus and Qdrant update methods#4568
Merged
kartik-mem0 merged 1 commit intomainfrom Mar 27, 2026
Merged
fix(vector_stores): handle vector=None in Milvus and Qdrant update methods#4568kartik-mem0 merged 1 commit intomainfrom
kartik-mem0 merged 1 commit intomainfrom
Conversation
…thods (#3708) Metadata-only updates (e.g. session ID changes) pass vector=None to vector_store.update(), which crashes on Milvus (DataNotMatchException) and Qdrant (PointStruct ValidationError). Milvus: fetch existing vector/payload via client.get() when either is None, so upsert always receives valid data. Qdrant: use native partial-update APIs (set_payload, update_vectors) instead of full upsert when only one of vector/payload is provided. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
5 tasks
kartik-mem0
approved these changes
Mar 27, 2026
This was referenced Mar 30, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #3708
Metadata-only updates (e.g. session ID changes at
mem0/memory/main.py:670and:1761) callvector_store.update(vector_id=..., vector=None, payload=...). This crashes on Milvus (DataNotMatchException— Milvus requires a valid float vector for every upsert) and Qdrant (ValidationError—PointStructrejectsvector=None).Problem
Milvus (
mem0/vector_stores/milvus.py):The
update()method unconditionally builds{"id": vector_id, "vectors": vector, "metadata": payload}and passes it toclient.upsert(). Whenvector=None, Milvus rejects the record because thevectorsfield expectsFLOAT_VECTORdata.Qdrant (
mem0/vector_stores/qdrant.py):The
update()method constructsPointStruct(id=vector_id, vector=vector, payload=payload). Qdrant's Pydantic model validation rejectsvector=Nonewith 6 validation errors.Both failures are triggered by the same call path — the session ID update logic in
Memory.add()andAsyncMemory.add():Solution
Milvus: When
vectororpayloadisNone, fetch the existing record viaclient.get()and use its stored vector/metadata to fill in the missing values before callingupsert(). A singleget()call is used even when both areNone. RaisesValueErrorwith clear messages if the record doesn't exist or has no vector data.Qdrant: Use Qdrant's native partial-update APIs instead of a full
upsert:vector=None→client.set_payload()(metadata-only update)payload=None→client.update_vectors()(vector-only update)client.upsert()(existing behavior, unchanged)Other vector stores reviewed
Nonenativelyif vector is not Noneguardif vector is not Noneguardis not NoneguardsNo other stores need fixes for this issue.
Testing
New tests added
Milvus (
tests/vector_stores/test_milvus.py) — 5 new tests:test_update_with_none_vector_fetches_existing— core bug fix: verifies existing vector is fetched and used whenvector=Nonetest_update_with_none_payload_fetches_existing— verifies existing metadata is preserved whenpayload=Nonetest_update_with_both_none_fetches_existing— verifies only oneclient.get()call when both areNonetest_update_with_none_vector_raises_on_missing_record— error handling for nonexistent recordstest_update_with_none_vector_raises_on_missing_vector_data— error handling for corrupt recordsQdrant (
tests/vector_stores/test_qdrant.py) — 3 new tests:test_update_with_none_vector_uses_set_payload— verifiesset_payloadis called instead ofupserttest_update_with_none_payload_uses_update_vectors— verifiesupdate_vectorsis called instead ofupserttest_update_with_both_none_is_noop— verifies no client calls when both areNoneBackward compatibility verified
test_update_uses_upsertwhich confirms the normal both-provided path is unchanged)test_updatewhich confirms the normal both-provided path is unchanged)redismodule)🤖 Generated with Claude Code