Skip to content

fix: do not mutate a reused vector_index_config when adding a quantizer - #2173

Open
joaquinhuigomez wants to merge 1 commit into
weaviate:mainfrom
joaquinhuigomez:fix/vector-index-config-not-shared
Open

joaquinhuigomez wants to merge 1 commit into
weaviate:mainfrom
joaquinhuigomez:fix/vector-index-config-not-shared

Conversation

@joaquinhuigomez

Copy link
Copy Markdown

Reusing one Configure.VectorIndex.hnsw(...) object across several Configure.Vectors.* calls leaks the quantizer requested for one vector onto all of them:

tuned = Configure.VectorIndex.hnsw(ef_construction=256, max_connections=64)
Configure.Vectors.self_provided(name="compressed", vector_index_config=tuned,
                                quantizer=Configure.VectorIndex.Quantizer.pq(segments=96))
Configure.Vectors.self_provided(name="raw", vector_index_config=tuned)

renders pq on both compressed and raw, and tuned itself is mutated. _IndexWrappers.single and .multi assign the quantizer (and, for multi-vectors, the encoding) directly onto the caller's object, so every vector built from the same variable shares one pydantic instance. It is silent, and because a quantizer cannot be changed after creation (__check_quantizers refuses), the collection has to be recreated. Same class of aliasing that #2143 fixed in _FilterBase._target_path.

Both wrappers now deep-copy vector_index_config before touching it; multi() also copies multi_vector_config, which had the identical problem with encoding. Four tests cover HNSW, dynamic (the quantizer fans out to both hnsw and flat), multi-vector, and a shared multi-vector config — each asserts the unquantized vector stays clean and the caller's object is unchanged. All fail on main. test/collection/test_config.py 211 passed; ruff, flake8 and pyright clean.

`_IndexWrappers.single()` and `.multi()` set the quantizer, the
multivector config and the encoding on the caller's object. Two vectors
built from one `Configure.VectorIndex.hnsw(...)` therefore ended up
holding the same pydantic instance, so a quantizer requested for one
vector was also sent for the other, and the caller's own object was
mutated as a side effect.

That is hard to undo: `_CollectionConfigUpdate` refuses to change a
quantizer after the collection has been created, so the collection has to
be dropped and recreated.

Copy the config objects before touching them, as weaviate#2143 did for
`_FilterBase._target_path`. `multi()` copies `multi_vector_config` too,
since it assigns the encoding onto it in the same way.

@orca-security-eu orca-security-eu Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Orca Security Scan Summary

Status Check Issues by priority
Passed Passed Infrastructure as Code high 0   medium 0   low 0   info 0 View in Orca
Passed Passed SAST high 0   medium 0   low 0   info 0 View in Orca
Passed Passed Secrets high 0   medium 0   low 0   info 0 View in Orca
Passed Passed Vulnerabilities high 0   medium 0   low 0   info 0 View in Orca

@weaviate-git-bot

Copy link
Copy Markdown

To avoid any confusion in the future about your contribution to Weaviate, we work with a Contributor License Agreement. If you agree, you can simply add a comment to this PR that you agree with the CLA so that we can merge.

beep boop - the Weaviate bot 👋🤖

PS:
Are you already a member of the Weaviate Forum?

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants