headroomlabs-ai/headroom · error · ValueError
Memory {memory.id} has no embedding
Error message
Memory {memory.id} has no embedding What it means
Raised by HNSWVectorIndex.add_memory (or add) when the Memory object passed in has memory.embedding set to None. The HNSW index only stores pre-computed vectors, so it refuses to index a memory that lacks one. Embedding must be produced by an external Embedder before indexing.
Source
Thrown at headroom/memory/adapters/hnsw.py:334
def size(self) -> int:
"""Return the number of vectors currently indexed."""
with self._lock:
return len(self._memory_to_hnsw)
async def index(self, memory: Memory) -> None:
"""Index a memory's embedding for similarity search.
The memory must have an embedding set. If max_entries is set and
the limit is reached, low-importance entries are evicted.
Args:
memory: The memory to index.
Raises:
ValueError: If the memory has no embedding or wrong dimension.
"""
if memory.embedding is None:
raise ValueError(f"Memory {memory.id} has no embedding")
embedding = np.asarray(memory.embedding, dtype=np.float32)
if embedding.shape[0] != self._dimension:
raise ValueError(
f"Embedding dimension {embedding.shape[0]} does not match "
f"index dimension {self._dimension}"
)
with self._lock:
# Check if already indexed - update if so
if memory.id in self._memory_to_hnsw:
await self._update_embedding_internal(memory.id, embedding)
# Update metadata
self._metadata[memory.id] = IndexedMemoryMetadata.from_memory(memory)
else:
# Evict if at capacity (before adding new entry)
if self._max_entries is not None:
current_size = len(self._memory_to_hnsw)View on GitHub (pinned to 322425c43b)
Solutions
- Run the memory through your Embedder (e.g. memory.embedding = await embedder.embed(memory.content)) before calling add_memory.
- Check memory.embedding is not None before indexing and route un-embedded memories to an embedding step.
- If embeddings are generated in a background task, await its completion before the index call.
Example fix
// before
await index.add_memory(memory) # memory.embedding is None
// after
if memory.embedding is None:
memory.embedding = await embedder.embed(memory.content)
await index.add_memory(memory) Defensive patterns
Strategy: validation
Validate before calling
if memory.embedding is None:
memory.embedding = await embedder.embed(memory.content)
await index.add_memory(memory) Type guard
def has_embedding(m: Memory) -> bool:
return m.embedding is not None Try / catch
try:
await index.add_memory(memory)
except ValueError as e:
if "no embedding" in str(e):
memory.embedding = await embedder.embed(memory.content)
await index.add_memory(memory)
else:
raise Prevention
- Make embedding a mandatory step in the ingest pipeline before any index call.
- Use a type hint MemoryWithEmbedding (NewType) to distinguish embedded memories in code.
When it happens
Trigger: Calling index.add_memory(memory) on a Memory that was never run through an Embedder; embedding a memory asynchronously and indexing before the embedding task finishes; loading memories from a store that did not persist embeddings.
Common situations: Pipeline ordering bugs where embed() and index() run in the wrong order; memories created from plain text and passed directly to the vector index; partial deserialization where the embedding column was null.
Related errors
- Embedding dimension {embedding.shape[0]} does not match inde
- Memory {memory.id} has no embedding
- hnsw_ef_construction must be positive, got {self.hnsw_ef_con
- hnsw_m must be positive, got {self.hnsw_m}
- hnsw_ef_search must be positive, got {self.hnsw_ef_search}
AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15).
Data as JSON: /api/errors/85405548f60963ba.
Report an issue: GitHub.