RyanCodrai/turbovec · error · ValueError

node embedding dim {vectors.shape[1]} does not match index d

Error message

node embedding dim {vectors.shape[1]} does not match index dim {existing_dim}

What it means

The store's underlying index already has a fixed vector dimension and the incoming node embeddings have a different width. For an eager (already-populated) index, adding mismatched-dim vectors would cause a Rust panic, so the Python layer pre-checks and raises a clean ValueError.

Source

Thrown at turbovec-python/python/turbovec/llama_index.py:401

        # PARENT / CHILD), excluded_*_metadata_keys, template fields,
        # start/end_char_idx and mimetype on retrieval. The narrow
        # `{text, metadata, ref_doc_id}` schema we used to keep lost
        # all of those silently.
        payloads = [_payload_for(node) for node in nodes]

        # Cosine mode: L2-normalize outside the lock (pure computation)
        # so the engine's raw inner product is true cosine similarity.
        # Zero rows pass through unchanged.
        if self._similarity == COSINE:
            vectors = l2_normalize_rows(vectors)

        with self._write_lock:
            # IdMapIndex.add_with_ids handles eager (dim must match) and lazy
            # (locks dim on first add) — pre-check the eager case so we
            # surface a clean ValueError rather than a Rust panic.
            existing_dim = self._index.dim
            if existing_dim is not None and vectors.shape[1] != existing_dim:
                raise ValueError(
                    f"node embedding dim {vectors.shape[1]} does not match index dim {existing_dim}"
                )
            if not vectors.flags["C_CONTIGUOUS"]:
                vectors = np.ascontiguousarray(vectors)

            handles = np.array([self._issue_handle() for _ in nodes], dtype=np.uint64)

            # Capture the previous state of any upserted node_id BEFORE the
            # maps are overwritten, so a failed index add can restore it and
            # the old vectors can be dropped once the add succeeds.
            old = [
                (nid, self._node_id_to_u64[nid], self._nodes[nid])
                for nid in node_ids
                if nid in self._node_id_to_u64
            ]

            # Maps BEFORE the index add: a concurrent query can only learn
            # a handle from the index, so an entry that is resolvable but

View on GitHub (pinned to ccab9f325e)

Solutions

  1. Rebuild the index from scratch with the new embed model instead of appending to the old one
  2. Ensure all documents are embedded with the same model used when the index dim was locked
  3. Delete the persisted index files and re-ingest the corpus

Example fix

// before
store = TurboQuantVectorStore(persist_path="old_index.tqv")  # 384-dim
store.add(new_1536_dim_nodes)
// after
store = TurboQuantVectorStore(persist_path=None)  # fresh index for new dim
store.add(new_1536_dim_nodes)
Defensive patterns

Strategy: validation

Validate before calling

dim = store._index.dim
if dim is not None and len(nodes[0].get_embedding()) != dim:
    raise ValueError(f"embedding dim {len(nodes[0].get_embedding())} != index dim {dim}")

Type guard

def dims_match(nodes, index_dim: int | None) -> bool:
    return index_dim is None or all(len(n.get_embedding()) == index_dim for n in nodes)

Try / catch

try:
    store.add(nodes)
except ValueError as e:
    if "does not match index dim" in str(e):
        raise RuntimeError("switched embed models? rebuild the index from scratch") from e
    raise

Prevention

When it happens

Trigger: Calling add() with embeddings of dimension D2 when the index was created/first-populated with dimension D1 — typically after switching embed models against an existing persisted index.

Common situations: Changing from one embed model (e.g. 384-dim MiniLM) to another (e.g. 1536-dim OpenAI) while reusing a persisted turbovec index; index dim locked by a previous first insert.

Understand the failure class

Background: Tensor shape mismatch errors ("must have shape", "expected shape ... got ..."): when tensor dimensions disagree with what an op or layer was told to expect — this error's family across 6 libraries.

Related errors


AI-assisted analysis of RyanCodrai/turbovec@ccab9f325e (2026-09-06). Data as JSON: /api/errors/ea02df7dd7632062. Report an issue: GitHub.