headroomlabs-ai/headroom · error · FileNotFoundError

Metadata file not found: {meta_path}

Error message

Metadata file not found: {meta_path}

What it means

Raised by HNSWVectorIndex.load_index when the .hnsw graph file exists but the companion .meta metadata file does not. The metadata file stores dimension and construction parameters needed to reconstruct the index, so a lone graph file is unusable.

Source

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

        """Load the index from disk.

        Loads both the HNSW index and all metadata/mappings.

        Args:
            path: Base path for the saved files.

        Raises:
            FileNotFoundError: If the index files don't exist.
            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"]

View on GitHub (pinned to 322425c43b)

Solutions

  1. Keep .hnsw and .meta together — copy/restore both files as a pair.
  2. If the .meta is lost, rebuild the index from source memories rather than trying to hand-craft metadata.
  3. Make saves atomic (write to temp files, then rename both) to avoid half-written pairs.

Example fix

// before
await index.load_index(path)

// after
if path.with_suffix('.hnsw').exists() and path.with_suffix('.meta').exists():
    await index.load_index(path)
else:
    await rebuild_index(index, memories)
Defensive patterns

Strategy: type-guard

Validate before calling

if not (path.with_suffix('.hnsw').exists() and path.with_suffix('.meta').exists()):
    await rebuild_index(index, memories)

Type guard

def index_pair_complete(base: Path) -> bool:
    return base.with_suffix('.hnsw').exists() and base.with_suffix('.meta').exists()

Try / catch

try:
    await index.load_index(path)
except FileNotFoundError as e:
    logger.warning("incomplete index at %s: %s; rebuilding", path, e)
    await rebuild_index(index, memories)

Prevention

When it happens

Trigger: A .hnsw file was copied or restored without its .meta sibling; partial writes or interrupted save_index; manual cleanup that deleted only one of the two files.

Common situations: Backup/restore scripts that glob only *.hnsw; sync tools excluding the .meta extension; crash between writing the two files during save_index.

Related errors


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