RyanCodrai/turbovec · error · ValueError

nodes have empty embeddings (dim 0); check the embed model t

Error message

nodes have empty embeddings (dim 0); check the embed model that produced them

What it means

The batch is 2D but its second axis is 0 — every node has a zero-length embedding. This passes the ndim guard but would crash deep inside the Rust index kernel with an opaque buffer error, so the library raises a clear ValueError naming the real cause instead.

Source

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

        except ValueError:
            seen: set[str] = set()
            dup = next(nid for nid in node_ids if nid in seen or seen.add(nid))
            raise ValueError(
                f"duplicate node_id {dup!r} appears multiple times "
                "in the input batch; deduplicate before calling add()"
            ) from None

        embeddings = [node.get_embedding() for node in nodes]
        vectors = np.asarray(embeddings, dtype=np.float32)
        if vectors.ndim != 2:
            raise ValueError(
                f"expected 2D embedding batch, got {vectors.ndim}D"
            )
        # A batch of empty per-node embeddings has shape (N, 0) — 2D, so
        # it passes the ndim guard, then dies deep in the index kernel
        # with an opaque buffer-length error. Name the real cause instead.
        if vectors.shape[1] == 0:
            raise ValueError(
                "nodes have empty embeddings (dim 0); check the embed "
                "model that produced them"
            )
        # Build every side-car payload BEFORE mutating any state, so a
        # payload failure (e.g. non-serializable metadata) leaves the
        # store untouched. `metadata` and `ref_doc_id` are kept at top
        # level for fast filter / doc-id lookup (queries hit these on
        # every hit; parsing _node_content per hit would be wasteful).
        # `node_dict` is the framework's canonical metadata representation
        # (`_node_content` + `_node_type` + original metadata keys),
        # which `metadata_dict_to_node` reconstructs into a full
        # BaseNode — preserving relationships (PREVIOUS / NEXT /
        # 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]

View on GitHub (pinned to ccab9f325e)

Solutions

  1. Run the embed model over node content and set node.embedding before add()
  2. Verify embeddings with `all(len(n.get_embedding()) > 0 for n in nodes)` before calling add()
  3. Check the embed model/config isn't silently returning empty vectors (e.g. missing API key, empty text input)

Example fix

// before
store.add(nodes)
// after
assert all(len(n.get_embedding()) > 0 for n in nodes), "node embeddings are empty"
store.add(nodes)
Defensive patterns

Strategy: validation

Validate before calling

if not nodes or any(len(n.get_embedding()) == 0 for n in nodes):
    raise ValueError("empty or missing embeddings before store.add()")

Type guard

def embeddings_present(nodes) -> bool:
    return bool(nodes) and all(n.get_embedding() is not None and len(n.get_embedding()) > 0 for n in nodes)

Try / catch

try:
    store.add(nodes)
except ValueError as e:
    if "empty embeddings" in str(e):
        raise RuntimeError("embed model produced empty vectors; check model config and input text") from e
    raise

Prevention

When it happens

Trigger: Calling add() with nodes whose get_embedding() returns [] or an empty array for every node — e.g. nodes constructed from documents without ever running the embed model, or an embed model configured to skip embedding.

Common situations: Forgetting to run an embedding step in a custom ingestion pipeline; an embed model returning [] on failure or empty text; loading nodes from storage without their embeddings.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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