headroomlabs-ai/headroom · error · ValueError

Saved index dimension {saved_dimension} does not match curre

Error message

Saved index dimension {saved_dimension} does not match current dimension {self._dimension}

What it means

Raised by HNSWVectorIndex.load_index when the dimension recorded in the .meta file differs from the current index instance's dimension. A saved HNSW graph can only be loaded into an index configured for the same vector space, so this guard prevents mixing incompatible embeddings.

Source

Thrown at headroom/memory/adapters/hnsw.py:863

            ValueError: If the saved dimension doesn't match.
        """
        path = Path(path)
        hnsw_path = path.with_suffix(".hnsw")
        meta_path = path.with_suffix(".meta")

        if not hnsw_path.exists():
            raise FileNotFoundError(f"HNSW index not found: {hnsw_path}")
        if not meta_path.exists():
            raise FileNotFoundError(f"Metadata file not found: {meta_path}")

        # Load metadata first to get parameters
        with open(meta_path) as f:
            meta_data = json.load(f)

        # Verify dimension matches
        saved_dimension = meta_data["dimension"]
        if saved_dimension != self._dimension:
            raise ValueError(
                f"Saved index dimension {saved_dimension} does not match "
                f"current dimension {self._dimension}"
            )

        with self._lock:
            # Update parameters
            self._max_elements = meta_data["max_elements"]
            self._ef_construction = meta_data["ef_construction"]
            self._m = meta_data["m"]
            self._ef_search = meta_data["ef_search"]

            # Restore bounding parameters (with defaults for backward compatibility)
            self._max_entries = meta_data.get("max_entries")
            self._eviction_batch_size = meta_data.get("eviction_batch_size", 100)
            self._eviction_count = meta_data.get("eviction_count", 0)

            # Create new index and load from file
            self._index = hnswlib.Index(space="cosine", dim=self._dimension)  # type: ignore[union-attr]

View on GitHub (pinned to 322425c43b)

Solutions

  1. Construct the index with the dimension recorded in the .meta file (read meta_data['dimension'] first), or re-embed everything and save a new index.
  2. After changing embedders, version your index paths (e.g. index-miniLM.hnsw vs index-llm.hnsw) so old files are never loaded with new dimensions.
  3. Delete the stale files and rebuild from the memory store.

Example fix

// before
index = HNSWVectorIndex(dimension=384)
await index.load_index(path)  # saved with 768

// after
meta = json.loads(path.with_suffix('.meta').read_text())
index = HNSWVectorIndex(dimension=meta['dimension'])
await index.load_index(path)
Defensive patterns

Strategy: validation

Validate before calling

meta = json.loads(path.with_suffix('.meta').read_text())
index = HNSWVectorIndex(dimension=meta['dimension'])
await index.load_index(path)

Try / catch

try:
    await index.load_index(path)
except ValueError as e:
    if "dimension" in str(e):
        # stale index from another model: rebuild
        await rebuild_index(index, memories)

Prevention

When it happens

Trigger: Constructing HNSWVectorIndex(dimension=384) (or using a default) then loading a file saved with dimension=768; loading an index saved before switching embedding models.

Common situations: Embedding model upgrade without recreating the on-disk index; environment-specific defaults disagreeing; the constructor default silently used instead of the model's dimension.

Related errors


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