chroma-core/chroma · error · ValueError
SparseVector indices must be sorted in strictly ascending or
Error message
SparseVector indices must be sorted in strictly ascending order, found indices[{i}]={self.indices[i]} <= indices[{i-1}]={self.indices[i-1]} What it means
SparseVector.__post_init__ enforces that indices are sorted in strictly ascending order - sorted and free of duplicates. Chroma's sparse matching code relies on this canonical form, and a duplicate index would make the index-to-value mapping ambiguous. The message pinpoints the first offending pair (indices[i] <= indices[i-1]), i.e. either an out-of-order entry or a duplicate.
Source
Thrown at chromadb/base_types.py:81
raise ValueError(
f"SparseVector indices must be integers, got {type(idx).__name__} at position {i}"
)
if idx < 0:
raise ValueError(
f"SparseVector indices must be non-negative, got {idx} at position {i}"
)
for i, val in enumerate(self.values):
if not isinstance(val, (int, float)):
raise ValueError(
f"SparseVector values must be numbers, got {type(val).__name__} at position {i}"
)
# Validate indices are sorted in strictly ascending order
if len(self.indices) > 1:
for i in range(1, len(self.indices)):
if self.indices[i] <= self.indices[i - 1]:
raise ValueError(
f"SparseVector indices must be sorted in strictly ascending order, "
f"found indices[{i}]={self.indices[i]} <= indices[{i-1}]={self.indices[i-1]}"
)
def to_dict(self) -> Dict[str, Any]:
"""Serialize to transport format with type tag.
Note: Uses 'tokens' as the wire format key name for compatibility
with the protobuf schema, even though the Python attribute is 'labels'.
"""
result = {
TYPE_KEY: SPARSE_VECTOR_TYPE_VALUE,
"indices": self.indices,
"values": self.values,
}
if self.labels is not None:
result["tokens"] = self.labels # Wire format uses 'tokens'
return resultView on GitHub (pinned to aecdd12c8a)
Solutions
- Build a dict index->value first (summing duplicates), then emit sorted: merged[i] = merged.get(i, 0.0) + v; indices = sorted(merged); values = [merged[i] for i in indices].
- If duplicates are impossible by construction, sort pairs: pairs = sorted(zip(indices, values)) and construct from that.
- Decide the duplicate policy explicitly (sum weights, take max, or keep first) instead of relying on input order.
Example fix
// before
sv = SparseVector(indices=[5, 3, 5], values=[0.2, 0.1, 0.3]) # ValueError: indices[2]=5 <= indices[1]=3
// after
merged = {}
for i, v in zip([5, 3, 5], [0.2, 0.1, 0.3]):
merged[i] = merged.get(i, 0.0) + v
sv = SparseVector(indices=sorted(merged), values=[merged[i] for i in sorted(merged)]) Defensive patterns
Strategy: validation
Validate before calling
def canonicalize(indices, values):
"""Merge duplicate indices (summing values) and sort ascending."""
merged = {}
for i, v in zip(indices, values):
merged[i] = merged.get(i, 0.0) + v
order = sorted(merged)
return order, [merged[i] for i in order]
indices, values = canonicalize(indices, values)
sv = SparseVector(indices=indices, values=values) Type guard
def is_strictly_ascending(xs) -> bool:
return all(b > a for a, b in zip(xs, xs[1:])) Try / catch
try:
sv = SparseVector(indices=indices, values=values)
except ValueError as e:
raise ValueError(f'sparse embedding not canonical for doc {doc_id}: {e}') from e Prevention
- Accumulate into dict[index -> value] while building the embedding; sort once at the end.
- Never concatenate two sparse vectors' lists - merge their dicts instead.
- Assert is_strictly_ascending(indices) in debug builds of your embedder.
When it happens
Trigger: Aggregating per-token entries by appending (e.g. bag-of-words where the same token appears twice, producing duplicate indices); concatenating two sparse vectors without merging; building indices from a dict/Counter without sorting; IDs inserted in document order instead of dimension order.
Common situations: Count-based sparse embeddings built by looping over tokens; unions of sparse vectors done via list concatenation; vocab IDs assumed sorted but aren't.
Related errors
- Sparse vector index must be created on a specific key. Pleas
- Deleting sparse vector index is not currently supported.
- Expected IDs to be unique, but found duplicates of ${duplica
- Expected IDs to be unique, but found duplicates of ${duplica
- SparseVector indices must be integers, got {type(idx).__name
AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16).
Data as JSON: /api/errors/0ca21ee2399e72f0.
Report an issue: GitHub.