[Bug]: SparseVector accepts non-finite values and non-string labels that fail at the transport boundary
What happened?
SparseVector.__post_init__ validates that values are numbers and that
labels is a list of matching length, but it does not check that float values
are finite or that each label is a string.
Two inputs are accepted that cannot be represented downstream:
- Non-finite float values:
from chromadb.base_types import SparseVector
sv = SparseVector(indices=[0], values=[float("nan")])
sv.to_dict()
# {'#type': 'sparse_vector', 'indices': [0], 'values': [nan]}The dict is serialized to JSON as {"values": [null]}, which fails f32
decoding server-side. If a null value is ever returned to the client,
SparseVector.from_dict raises ValueError on it as well:
SparseVector.from_dict({"#type": "sparse_vector", "indices": [0], "values": [None]})
# ValueError: SparseVector values must be numbers, got NoneType at position 0- Non-string labels:
SparseVector(indices=[0], values=[1.0], labels=[123])
# accepted; to_dict() emits {"tokens": [123]}, which fails string[] decodingExpected behavior
Both cases should be rejected at construction with a clear ValueError, the
same way non-numeric values and unsorted indices already are.
Versions
chromadb 1.5.9 (current main), Python 3.12.
Proposed fix
In SparseVector.__post_init__, reject non-finite float values
(math.isfinite) and non-str labels. This is the same fail-fast treatment
metadata floats need (see also the discussion around non-finite metadata
values), applied to sparse vector values and labels.
Source: chroma-core/chroma