headroomlabs-ai/headroom · error · ValueError

Embedding dimension {embedding.shape[0]} does not match inde

Error message

Embedding dimension {embedding.shape[0]} does not match index dimension {self._dimension}

What it means

Raised by SQLiteVectorIndex._prepare_memory_for_index when the memory's embedding length differs from the dimension the index was created with (default 384 for MiniLM). The vec0 virtual table is fixed-dimension, so mismatched vectors are rejected before insert.

Source

Thrown at headroom/memory/adapters/sqlite_vector.py:300

        rowids: dict[str, int] = {}
        for chunk in self._chunked(memory_ids):
            placeholders = ", ".join("?" for _ in chunk)
            rows = conn.execute(
                f"SELECT rowid, memory_id FROM vec_metadata WHERE memory_id IN ({placeholders})",
                chunk,
            ).fetchall()
            for row in rows:
                rowids[str(row["memory_id"])] = int(row["rowid"])
        return rowids

    def _prepare_memory_for_index(self, memory: Memory) -> tuple[np.ndarray, VectorMetadata]:
        """Validate a memory and prepare it for indexing."""
        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}"
            )

        return embedding, VectorMetadata.from_memory(memory)

    def _metadata_insert_params(self, memory_id: str, metadata: VectorMetadata) -> tuple[Any, ...]:
        """Build INSERT parameters for vector metadata."""
        return (
            memory_id,
            metadata.user_id,
            metadata.session_id,
            metadata.agent_id,
            metadata.importance,
            metadata.created_at.isoformat(),
            metadata.valid_until.isoformat() if metadata.valid_until else None,
            json.dumps(metadata.entity_refs),
            metadata.content,

View on GitHub (pinned to 322425c43b)

Solutions

  1. Pass dimension=embedder.dimension when constructing SQLiteVectorIndex.
  2. If the model changed, drop/recreate the vec0 table (or use a new db_path) and re-index.
  3. Log embedding length at ingest to catch drift early.

Example fix

// before
index = SQLiteVectorIndex(db_path=p)  # default 384, embedder gives 1536

// after
index = SQLiteVectorIndex(dimension=embedder.dimension, db_path=p)
Defensive patterns

Strategy: validation

Validate before calling

if np.asarray(memory.embedding).shape[0] != index.dimension:
    raise RuntimeError("embedding/model mismatch against vec0 table")

Prevention

When it happens

Trigger: Using the default dimension=384 with an embedder that outputs another size (e.g. 768 or 1536); switching embedding models against an existing database; indexing mixed-source embeddings.

Common situations: Relying on the MiniLM default while using OpenAI or another model; model upgrades without recreating the vector table; environments with different embedders sharing one db_path.

Related errors


AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15). Data as JSON: /api/errors/1a8a8887629b8ce7. Report an issue: GitHub.