RyanCodrai/turbovec · error · ValueError
Document {doc.id!r} has no embedding. TurboQuantDocumentStor
Error message
Document {doc.id!r} has no embedding. TurboQuantDocumentStore only stores documents with precomputed embeddings — run an embedder component before writing. What it means
Raised in _write_documents_locked when a Document has embedding=None. TurboQuantDocumentStore stores only precomputed embeddings — there is no embedder inside the store — so writing an un-embedded document would create an unsearchable entry. It fires in both the FAIL path and the SKIP/OVERWRITE validation pass.
Source
Thrown at turbovec-python/python/turbovec/haystack.py:266
# stays persisted — a partial write. Mirror that observable
# state exactly: validate and commit per document, raising on
# the first collision. A repeated id within a single call
# collides with its already-committed first instance, the same
# way a cross-call repeat would. Each individual commit is
# still all-or-nothing — validation precedes any mutation, so
# a failing document mid-batch never leaves the index and the
# id maps inconsistent (#89/#139 apply per document).
written = 0
for doc in documents:
if doc.id in self._str_to_u64:
# Checked before embedding validation: the reference
# raises DuplicateDocumentError for a colliding id
# regardless of the document's other fields.
raise DuplicateDocumentError(
f"ID '{doc.id}' already exists in the document store."
)
if doc.embedding is None:
raise ValueError(
f"Document {doc.id!r} has no embedding. "
"TurboQuantDocumentStore only stores documents with precomputed "
"embeddings — run an embedder component before writing."
)
self._commit_batch([doc])
written += 1
return written
# SKIP / OVERWRITE: first pass validates and resolves duplicates
# against the batch-so-far as well as the existing store:
# InMemoryDocumentStore writes into its dict as it iterates, so a
# repeated id *within a single call* is resolved the same way a
# cross-call repeat would be. Without tracking the batch, every
# duplicate row still gets its own vector while _str_to_u64 keeps
# only the last handle, orphaning the earlier vectors.
to_write: List[Document] = []
batch_pos: Dict[str, int] = {} # doc.id -> index into to_write
to_remove: List[str] = [] # existing ids to drop, deferred past addView on GitHub (pinned to ccab9f325e)
Solutions
- Run a haystack Embedder component (e.g. SentenceTransformersDocumentEmbedder) on the documents before write_documents.
- Check the pipeline wiring: the embedder step may have been skipped or produced None for some documents.
- Catch the ValueError in ingestion code to identify which document ids lack embeddings.
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at turbovec-python/python/turbovec/haystack.py:266 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of RyanCodrai/turbovec@ccab9f325e (2026-09-06).
Data as JSON: /api/errors/68f82fd6c96a4e2d.
Report an issue: GitHub.