{"record":{"id":"e3da8a81d7decbf2","repo":"RyanCodrai/turbovec","slug":"documents-have-empty-embeddings-dim-0-check-the","errorCode":null,"errorMessage":"documents have empty embeddings (dim 0); check the embedder that produced them","messagePattern":"documents have empty embeddings \\(dim 0\\); check the embedder that produced them","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"turbovec-python/python/turbovec/haystack.py","lineNumber":344,"sourceCode":"        precedes any mutation, and if the index add fails the\n        pre-inserted map entries are unwound (restoring the previous\n        mapping of any overwritten id), so a failure leaves the store\n        exactly as it was (issue #89). The FAIL path calls this with\n        single-document batches to get per-document commit semantics.\n        Callers hold the writer lock.\n        \"\"\"\n        vectors = np.asarray(\n            [doc.embedding for doc in to_write], dtype=np.float32\n        )\n        if vectors.ndim != 2:\n            raise ValueError(\n                f\"expected 2D embedding batch, got {vectors.ndim}D\"\n            )\n        # A batch of empty per-document embeddings has shape (N, 0) — 2D,\n        # so it passes the ndim guard, then dies deep in the index kernel\n        # with an opaque buffer-length error. Name the real cause instead.\n        if vectors.shape[1] == 0:\n            raise ValueError(\n                \"documents have empty embeddings (dim 0); check the \"\n                \"embedder that produced them\"\n            )\n        # IdMapIndex.add_with_ids handles both eager (dim must match) and\n        # lazy (locks dim on first call) cases. Surface its mismatch\n        # panic as a clean ValueError for parity with previous behaviour.\n        existing_dim = self._index.dim\n        if existing_dim is not None and vectors.shape[1] != existing_dim:\n            raise ValueError(\n                f\"embedding dim {vectors.shape[1]} does not match store dim {existing_dim}\"\n            )\n        if not vectors.flags[\"C_CONTIGUOUS\"]:\n            vectors = np.ascontiguousarray(vectors)\n        # Cosine mode: L2-normalize so the kernel's raw score is true\n        # cosine similarity. Pure numpy on the just-built batch (no\n        # embedder call — Haystack documents arrive pre-embedded), so\n        # doing it alongside the rest of the batch prep under the\n        # caller's writer lock adds no blocking work. Zero rows pass","sourceCodeStart":326,"sourceCodeEnd":362,"githubUrl":"https://github.com/RyanCodrai/turbovec/blob/ccab9f325e6ce2a270a87daf01ae4e443bcf2d49/turbovec-python/python/turbovec/haystack.py#L326-L362","documentation":"Raised in _commit_batch when the batch is 2D but with second dimension 0 — i.e. every document has a zero-length embedding, shape (N, 0). This passes the ndim guard but would otherwise die deep in the index kernel with an opaque buffer-length error; the store names the real cause: the embedder produced empty vectors.","triggerScenarios":"Thrown at turbovec-python/python/turbovec/haystack.py:344 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Check the embedder component that produced the documents — empty vectors usually mean an empty input text path or a broken model.","Validate embedding length at embed time before handing documents to the store.","Catch the ValueError in pipeline code to fail the indexing step with a clear embedder-related message."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"ccab9f325e6ce2a270a87daf01ae4e443bcf2d49","analyzedAt":"2026-09-06T08:39:18.516Z","contentChangedAt":"2026-09-06T08:39:18.516Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}