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 result

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. 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].
  2. If duplicates are impossible by construction, sort pairs: pairs = sorted(zip(indices, values)) and construct from that.
  3. 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

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


AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16). Data as JSON: /api/errors/0ca21ee2399e72f0. Report an issue: GitHub.