headroomlabs-ai/headroom · error · ValueError

hnsw_m must be positive, got {self.hnsw_m}

Error message

hnsw_m must be positive, got {self.hnsw_m}

What it means

ValueError raised in MemoryConfig.__post_init__ when hnsw_m < 1. hnsw_m is the HNSW graph fan-out (max connections per node); it must be at least 1 for the index to be constructible, and the guard rejects invalid values at config time rather than deep inside index building.

Source

Thrown at headroom/memory/config.py:145

    cache_enabled: bool = True
    cache_max_size: int = 1000

    # Bubbling defaults
    auto_bubble: bool = True
    bubble_threshold: float = 0.7  # Minimum importance for bubbling

    def __post_init__(self) -> None:
        """Validate configuration after initialization."""
        if self.vector_dimension < 1:
            raise ValueError(f"vector_dimension must be positive, got {self.vector_dimension}")

        if self.hnsw_ef_construction < 1:
            raise ValueError(
                f"hnsw_ef_construction must be positive, got {self.hnsw_ef_construction}"
            )

        if self.hnsw_m < 1:
            raise ValueError(f"hnsw_m must be positive, got {self.hnsw_m}")

        if self.hnsw_ef_search < 1:
            raise ValueError(f"hnsw_ef_search must be positive, got {self.hnsw_ef_search}")

        if self.cache_max_size < 1:
            raise ValueError(f"cache_max_size must be positive, got {self.cache_max_size}")

        if self.embedder_backend == EmbedderBackend.OPENAI and not self.openai_api_key:
            raise ValueError("openai_api_key is required when using OpenAI embedder backend")

        # Ensure db_path is a Path object
        if isinstance(self.db_path, str):
            self.db_path = Path(self.db_path)

View on GitHub (pinned to 322425c43b)

Solutions

  1. Use a positive value, typically 8-48 (16 is a common default); or omit the field for defaults
  2. Sanitize generated configs: treat 0/empty numeric fields as 'unset' and drop them before construction
  3. Add a config lint step in CI for memory settings

Example fix

# before
cfg = MemoryConfig(hnsw_m=0)  # ValueError: hnsw_m must be positive

# after
cfg = MemoryConfig(hnsw_m=16)
Defensive patterns

Strategy: validation

Validate before calling

def positive_int(name: str, v: int) -> int:
    if v < 1:
        raise ValueError(f'{name} must be >= 1, got {v}')
    return v

cfg = MemoryConfig(hnsw_m=positive_int('hnsw_m', raw_m))

Type guard

def is_positive_int(v) -> bool:
    return isinstance(v, int) and not isinstance(v, bool) and v >= 1

Try / catch

try:
    cfg = MemoryConfig(hnsw_m=raw_m)
except ValueError as e:
    raise SystemExit(f'Bad memory config: {e}') from e

Prevention

When it happens

Trigger: MemoryConfig(hnsw_m=0) or negative, typically from a template placeholder, an unset env var coerced to 0, or hand-tuned YAML with a typo.

Common situations: Config files with commented-out defaults replaced by 0; automation writing '0' for missing numeric fields; tuning copied from a different ANN library's scale.

Related errors


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