{"record":{"id":"0a3e7ba265d7809c","repo":"chroma-core/chroma","slug":"expected-dict-with-type-key-sparse-vector-type","errorCode":null,"errorMessage":"Expected dict with {TYPE_KEY}='{SPARSE_VECTOR_TYPE_VALUE}', got {query}","messagePattern":"Expected dict with (.+?)='(.+?)', got (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"chromadb/execution/expression/operator.py","lineNumber":705,"sourceCode":"            return Val(value)\n\n        elif op == \"$knn\":\n            knn_data = data[\"$knn\"]\n            if not isinstance(knn_data, dict):\n                raise TypeError(f\"$knn requires a dict, got {type(knn_data).__name__}\")\n\n            if \"query\" not in knn_data:\n                raise ValueError(\"$knn requires 'query' field\")\n\n            query = knn_data[\"query\"]\n\n            if isinstance(query, dict):\n                # SparseVector case - deserialize from transport format\n                if query.get(TYPE_KEY) == SPARSE_VECTOR_TYPE_VALUE:\n                    query = SparseVector.from_dict(query)\n                else:\n                    # Old format or invalid - try to construct directly\n                    raise ValueError(\n                        f\"Expected dict with {TYPE_KEY}='{SPARSE_VECTOR_TYPE_VALUE}', got {query}\"\n                    )\n\n            elif isinstance(query, (list, tuple, np.ndarray)):\n                # Dense vector case - normalize then validate\n                normalized = normalize_embeddings(query)\n                if not normalized or len(normalized) > 1:\n                    raise ValueError(\"$knn requires exactly one query embedding\")\n\n                # Validate the normalized version\n                validate_embeddings(normalized)\n\n                query = normalized[0]\n\n            else:\n                raise TypeError(\n                    f\"$knn query must be a list, numpy array, or SparseVector dict, got {type(query).__name__}\"\n                )","sourceCodeStart":687,"sourceCodeEnd":723,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/chromadb/execution/expression/operator.py#L687-L723","documentation":"When $knn's 'query' is a dict, the parser expects the SparseVector transport format, which is tagged with a discriminator: {'#type': 'sparse_vector', 'indices': [...], 'values': [...], 'tokens': [...]} (TYPE_KEY='#type', SPARSE_VECTOR_TYPE_VALUE='sparse_vector', chromadb/base_types.py:8-9). A dict without that exact marker - old formats or hand-built {'indices', 'values'} dicts - is rejected with this ValueError.","triggerScenarios":"Search(rank={'$knn': {'query': {'indices': [0, 2], 'values': [0.1, 0.3]}}}) with no #type key; embedding dicts persisted before the type tag existed; sparse queries assembled by hand from tokenizer output.","commonSituations":"Storing SparseVector fields in your own DB as {indices, values} and feeding them back into $knn; upgrading Chroma versions where older payloads lack the discriminator; using 'type' instead of '#type' as the key.","solutions":["Add the tag: {'#type': 'sparse_vector', **sparse_dict}.","Build the payload with SparseVector(indices=..., values=...).to_dict() so the tag is always correct.","For dense queries, pass a list/array instead of a dict."],"exampleFix":"# before\nquery = {'indices': [0, 2], 'values': [0.1, 0.3]}\nSearch(rank={'$knn': {'query': query}})    # -> ValueError\n\n# after\nfrom chromadb.base_types import SparseVector\nquery = SparseVector(indices=[0, 2], values=[0.1, 0.3]).to_dict()\nSearch(rank={'$knn': {'query': query}})","handlingStrategy":"validation","validationCode":"from chromadb.base_types import SparseVector\n\ndef sparse_query(indices, values, labels=None):\n    return SparseVector(indices=indices, values=values, labels=labels).to_dict()\n\nSearch(rank={'$knn': {'query': sparse_query([0, 2], [0.1, 0.3])}})","typeGuard":"from chromadb.base_types import TYPE_KEY, SPARSE_VECTOR_TYPE_VALUE\n\ndef is_sparse_vector_dict(d) -> bool:\n    return isinstance(d, dict) and d.get(TYPE_KEY) == SPARSE_VECTOR_TYPE_VALUE","tryCatchPattern":null,"preventionTips":["Never hand-write sparse query dicts - use SparseVector.to_dict().","Store the full to_dict() payload (including #type) when persisting embeddings.","The discriminator key is '#type' with a hash prefix, not 'type'."],"tags":["validation","valueerror","knn","sparse-vector","serialization","chromadb"],"backgroundTag":"invalid-discriminator-value","analyzedSha":"aecdd12c8a891610db8653630b066b32ceb678b5","analyzedAt":"2026-08-16T21:53:27.228Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}