{"record":{"id":"c8cbf4e22f3a1845","repo":"chroma-core/chroma","slug":"sparsevector-indices-must-be-integers-got-type-i","errorCode":null,"errorMessage":"SparseVector indices must be integers, got {type(idx).__name__} at position {i}","messagePattern":"SparseVector indices must be integers, got (.+?) at position (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"chromadb/base_types.py","lineNumber":63,"sourceCode":"            raise ValueError(\n                f\"SparseVector indices and values must have the same length, \"\n                f\"got {len(self.indices)} indices and {len(self.values)} values\"\n            )\n\n        if self.labels is not None:\n            if not isinstance(self.labels, list):\n                raise ValueError(\n                    f\"Expected SparseVector labels to be a list, got {type(self.labels).__name__}\"\n                )\n            if len(self.labels) != len(self.indices):\n                raise ValueError(\n                    f\"SparseVector labels must have the same length as indices and values, \"\n                    f\"got {len(self.labels)} labels, {len(self.indices)} indices\"\n                )\n\n        for i, idx in enumerate(self.indices):\n            if not isinstance(idx, int):\n                raise ValueError(\n                    f\"SparseVector indices must be integers, got {type(idx).__name__} at position {i}\"\n                )\n            if idx < 0:\n                raise ValueError(\n                    f\"SparseVector indices must be non-negative, got {idx} at position {i}\"\n                )\n\n        for i, val in enumerate(self.values):\n            if not isinstance(val, (int, float)):\n                raise ValueError(\n                    f\"SparseVector values must be numbers, got {type(val).__name__} at position {i}\"\n                )\n\n        # Validate indices are sorted in strictly ascending order\n        if len(self.indices) > 1:\n            for i in range(1, len(self.indices)):\n                if self.indices[i] <= self.indices[i - 1]:\n                    raise ValueError(","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/chromadb/base_types.py#L45-L81","documentation":"Chroma's SparseVector dataclass (chromadb/base_types.py) fully validates itself in __post_init__ at construction time. This ValueError means at least one element of `indices` is not a true Python `int` as checked by `isinstance(idx, int)`. NumPy scalars (np.int64, np.int32), floats like 3.0, and numeric strings all fail this check even though they look like valid indices; the message names the offending type and its list position.","triggerScenarios":"Constructing SparseVector(indices=..., values=...) where indices came from NumPy operations without conversion, e.g. np.argwhere(...).flatten(), indexing a numpy array (arr[i] yields np.int64), or from JSON/YAML/config data where indices were parsed as strings ('3') or floats (3.0).","commonSituations":"Custom sparse embedders whose tokenizer vocab IDs are NumPy scalars; ML pipelines that pass tensor/array elements straight into Chroma; config- or JSON-driven dimension indices that were never cast to int.","solutions":["Convert before constructing: indices = [int(i) for i in indices] (and values = [float(v) for v in values]).","If the data comes from a NumPy array, call .tolist() on it - it produces native Python ints/floats.","Use the type name and position in the error message to find the offending element and fix the producer that emits it."],"exampleFix":"// before\nimport numpy as np\nidx = np.argwhere(mask).flatten()  # dtype int64 -> np.int64 elements\nsv = SparseVector(indices=list(idx), values=vals)  # ValueError: got int64\n\n// after\nidx = np.argwhere(mask).flatten().tolist()  # native Python ints\nsv = SparseVector(indices=idx, values=vals)","handlingStrategy":"validation","validationCode":"# Normalize before constructing SparseVector\ndef to_int_indices(indices):\n    return [int(i) for i in indices]  # rejects non-numeric garbage loudly\n\nraw = np.argwhere(mask).flatten()\nindices = to_int_indices(raw)  # np.int64 -> int\nvalues = [float(v) for v in raw_values]\nsv = SparseVector(indices=indices, values=values)","typeGuard":"from typing import List\n\ndef is_int_index_list(xs: object) -> bool:\n    \"\"\"Matches Chroma's check: isinstance(idx, int) for every element.\"\"\"\n    return isinstance(xs, list) and all(isinstance(x, int) for x in xs)","tryCatchPattern":"try:\n    sv = SparseVector(indices=indices, values=values)\nexcept ValueError as e:\n    raise ValueError(f'invalid sparse embedding for doc {doc_id}: {e}') from e","preventionTips":["Call .tolist() on NumPy arrays at the boundary - it yields native Python ints/floats.","Keep sparse embeddings as dict[index -> value] internally and only materialize lists at the Chroma call site.","Add a unit test that constructs SparseVector from your real encoder output; it catches NumPy scalar leakage immediately."],"tags":["sparse-vector","type-validation","numpy","python"],"backgroundTag":"sparse-vector-validation","analyzedSha":"aecdd12c8a891610db8653630b066b32ceb678b5","analyzedAt":"2026-08-16T21:53:27.228Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}