{"record":{"id":"954a9c3089548f7c","repo":"chroma-core/chroma","slug":"expected-type-sparse-vector-got-d-get-type-ke","errorCode":null,"errorMessage":"Expected #type='sparse_vector', got {d.get(TYPE_KEY)}","messagePattern":"Expected #type='sparse_vector', got (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"chromadb/base_types.py","lineNumber":109,"sourceCode":"        \"\"\"\n        result = {\n            TYPE_KEY: SPARSE_VECTOR_TYPE_VALUE,\n            \"indices\": self.indices,\n            \"values\": self.values,\n        }\n        if self.labels is not None:\n            result[\"tokens\"] = self.labels  # Wire format uses 'tokens'\n        return result\n\n    @classmethod\n    def from_dict(cls, d: Dict[str, Any]) -> \"SparseVector\":\n        \"\"\"Deserialize from transport format (strict - requires #type field).\n\n        Note: Reads from 'tokens' key in the wire format for compatibility\n        with the protobuf schema, mapping it to the 'labels' attribute.\n        \"\"\"\n        if d.get(TYPE_KEY) != SPARSE_VECTOR_TYPE_VALUE:\n            raise ValueError(\n                f\"Expected {TYPE_KEY}='{SPARSE_VECTOR_TYPE_VALUE}', got {d.get(TYPE_KEY)}\"\n            )\n        return cls(\n            indices=d[\"indices\"],\n            values=d[\"values\"],\n            labels=d.get(\"tokens\"),  # Wire format uses 'tokens'\n        )\n\n\nMetadataListValue = List[Union[str, int, float, bool]]\nMetadata = Mapping[\n    str, Optional[Union[str, int, float, bool, SparseVector, MetadataListValue]]\n]\nUpdateMetadata = Mapping[\n    str, Union[int, float, str, bool, SparseVector, MetadataListValue, None]\n]\nPyVector = Union[Sequence[float], Sequence[int]]\nVector = NDArray[Union[np.int32, np.float32]]  # TODO: Specify that the vector is 1D","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/chromadb/base_types.py#L91-L127","documentation":"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.","triggerScenarios":"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.","commonSituations":"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 '#'.","solutions":["Add the tag before deserializing: d['#type'] = 'sparse_vector' (labels go under the 'tokens' key).","Produce wire dicts with SparseVector.to_dict() so '#type' is always present on the write side.","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'))."],"exampleFix":"// before\nd = {'indices': [1, 5], 'values': [0.2, 0.4]}\nsv = SparseVector.from_dict(d)  # ValueError: got None\n\n// after\nd = {'#type': 'sparse_vector', 'indices': [1, 5], 'values': [0.2, 0.4]}\nsv = SparseVector.from_dict(d)","handlingStrategy":"validation","validationCode":"TYPE_KEY, SPARSE_VECTOR_TYPE_VALUE = '#type', 'sparse_vector'\n\nif d.get(TYPE_KEY) != SPARSE_VECTOR_TYPE_VALUE:\n    # only add the tag if you KNOW the dict is a sparse vector payload\n    d = {**d, TYPE_KEY: SPARSE_VECTOR_TYPE_VALUE}\nsv = SparseVector.from_dict(d)  # labels are read from the 'tokens' key","typeGuard":"def is_sparse_vector_dict(d: object) -> bool:\n    return (\n        isinstance(d, dict)\n        and d.get('#type') == 'sparse_vector'\n        and isinstance(d.get('indices'), list)\n        and isinstance(d.get('values'), list)\n    )","tryCatchPattern":"try:\n    sv = SparseVector.from_dict(d)\nexcept ValueError as e:\n    raise ValueError(f'payload is not a tagged sparse vector: {e}') from e","preventionTips":["Always write sparse vectors with SparseVector.to_dict() so '#type' is present by construction.","Keep '#'-prefixed keys intact through any serialization middleware - do not strip unknown keys.","Version your stored payloads and re-validate with is_sparse_vector_dict before deserializing."],"tags":["sparse-vector","serialization","wire-format"],"backgroundTag":"invalid-message-format","analyzedSha":"aecdd12c8a891610db8653630b066b32ceb678b5","analyzedAt":"2026-08-16T21:53:27.228Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}