chroma-core/chroma · error · ValueError

Expected #type='sparse_vector', got {d.get(TYPE_KEY)}

Error message

Expected #type='sparse_vector', got {d.get(TYPE_KEY)}

What it means

SparseVector.from_dict (chromadb/base_types.py) is the strict deserializer for the tagged wire format. It requires d['#type'] == 'sparse_vector' (TYPE_KEY / SPARSE_VECTOR_TYPE_VALUE) and raises ValueError showing the value it actually found (commonly None). Plain dicts like {'indices': [...], 'values': [...]} are rejected because the tag is what distinguishes a sparse vector from arbitrary metadata.

Source

Thrown at chromadb/base_types.py:109

        """
        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

    @classmethod
    def from_dict(cls, d: Dict[str, Any]) -> "SparseVector":
        """Deserialize from transport format (strict - requires #type field).

        Note: Reads from 'tokens' key in the wire format for compatibility
        with the protobuf schema, mapping it to the 'labels' attribute.
        """
        if d.get(TYPE_KEY) != SPARSE_VECTOR_TYPE_VALUE:
            raise ValueError(
                f"Expected {TYPE_KEY}='{SPARSE_VECTOR_TYPE_VALUE}', got {d.get(TYPE_KEY)}"
            )
        return cls(
            indices=d["indices"],
            values=d["values"],
            labels=d.get("tokens"),  # Wire format uses 'tokens'
        )


MetadataListValue = List[Union[str, int, float, bool]]
Metadata = Mapping[
    str, Optional[Union[str, int, float, bool, SparseVector, MetadataListValue]]
]
UpdateMetadata = Mapping[
    str, Union[int, float, str, bool, SparseVector, MetadataListValue, None]
]
PyVector = Union[Sequence[float], Sequence[int]]
Vector = NDArray[Union[np.int32, np.float32]]  # TODO: Specify that the vector is 1D

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Add the tag before deserializing: d['#type'] = 'sparse_vector' (labels go under the 'tokens' key).
  2. Produce wire dicts with SparseVector.to_dict() so '#type' is always present on the write side.
  3. For untrusted input, check d.get('#type') first, or bypass from_dict and construct directly: SparseVector(indices=d['indices'], values=d['values'], labels=d.get('tokens')).

Example fix

// before
d = {'indices': [1, 5], 'values': [0.2, 0.4]}
sv = SparseVector.from_dict(d)  # ValueError: got None

// after
d = {'#type': 'sparse_vector', 'indices': [1, 5], 'values': [0.2, 0.4]}
sv = SparseVector.from_dict(d)
Defensive patterns

Strategy: validation

Validate before calling

TYPE_KEY, SPARSE_VECTOR_TYPE_VALUE = '#type', 'sparse_vector'

if d.get(TYPE_KEY) != SPARSE_VECTOR_TYPE_VALUE:
    # only add the tag if you KNOW the dict is a sparse vector payload
    d = {**d, TYPE_KEY: SPARSE_VECTOR_TYPE_VALUE}
sv = SparseVector.from_dict(d)  # labels are read from the 'tokens' key

Type guard

def is_sparse_vector_dict(d: object) -> bool:
    return (
        isinstance(d, dict)
        and d.get('#type') == 'sparse_vector'
        and isinstance(d.get('indices'), list)
        and isinstance(d.get('values'), list)
    )

Try / catch

try:
    sv = SparseVector.from_dict(d)
except ValueError as e:
    raise ValueError(f'payload is not a tagged sparse vector: {e}') from e

Prevention

When it happens

Trigger: Calling SparseVector.from_dict() on a hand-built dict that lacks the '#type' key; round-tripping a to_dict() result through code that strips unknown keys (e.g. a strict schema or a different library version); passing another type's tagged dict.

Common situations: Reading sparse vectors back from user-managed storage (JSON files, other DBs) where the producer never wrote '#type'; version mismatches where an older Chroma wrote dicts without the tag; middleware that filters keys starting with '#'.

Related errors


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