{"record":{"id":"871d6b9e5db6662d","repo":"headroomlabs-ai/headroom","slug":"hnsw-index-not-found-hnsw-path","errorCode":null,"errorMessage":"HNSW index not found: {hnsw_path}","messagePattern":"HNSW index not found: (.+?)","errorType":"exception","errorClass":"FileNotFoundError","httpStatus":null,"severity":"error","filePath":"headroom/memory/adapters/hnsw.py","lineNumber":852,"sourceCode":"\n    def load_index(self, path: str | Path) -> None:\n        \"\"\"Load the index from disk.\n\n        Loads both the HNSW index and all metadata/mappings.\n\n        Args:\n            path: Base path for the saved files.\n\n        Raises:\n            FileNotFoundError: If the index files don't exist.\n            ValueError: If the saved dimension doesn't match.\n        \"\"\"\n        path = Path(path)\n        hnsw_path = path.with_suffix(\".hnsw\")\n        meta_path = path.with_suffix(\".meta\")\n\n        if not hnsw_path.exists():\n            raise FileNotFoundError(f\"HNSW index not found: {hnsw_path}\")\n        if not meta_path.exists():\n            raise FileNotFoundError(f\"Metadata file not found: {meta_path}\")\n\n        # Load metadata first to get parameters\n        with open(meta_path) as f:\n            meta_data = json.load(f)\n\n        # Verify dimension matches\n        saved_dimension = meta_data[\"dimension\"]\n        if saved_dimension != self._dimension:\n            raise ValueError(\n                f\"Saved index dimension {saved_dimension} does not match \"\n                f\"current dimension {self._dimension}\"\n            )\n\n        with self._lock:\n            # Update parameters\n            self._max_elements = meta_data[\"max_elements\"]","sourceCodeStart":834,"sourceCodeEnd":870,"githubUrl":"https://github.com/headroomlabs-ai/headroom/blob/322425c43bffde1ed0b64fecf3cf5951565dd82b/headroom/memory/adapters/hnsw.py#L834-L870","documentation":"Raised by HNSWVectorIndex.load_index when the expected .hnsw graph file does not exist at the derived path (path.with_suffix('.hnsw')). The loader treats a missing index file as a hard error rather than silently starting empty, so callers must handle first-run scenarios explicitly.","triggerScenarios":"Calling load_index on a fresh install where nothing was saved yet; passing a base path whose suffix substitution points elsewhere (e.g. 'index.v1' becomes 'index.hnsw'); deleted or moved index files.","commonSituations":"First run of an app before any save_index; typos in the path; with_suffix('.hnsw') surprising developers who expected the literal filename to be used; clearing caches/data directories.","solutions":["Guard with Path.exists(): if the .hnsw file is absent, build a fresh index (and optionally save it) instead of loading.","Verify the exact derived path — load_index appends '.hnsw' via with_suffix, so 'myindex' loads 'my.hnsw' if the stem looks like a suffix; prefer a path without dots.","If the file was deleted unintentionally, restore it or re-index from the source of truth."],"exampleFix":"// before\nawait index.load_index(path)  # crashes on first run\n\n// after\nif path.with_suffix('.hnsw').exists():\n    await index.load_index(path)\nelse:\n    for m in memories:\n        await index.add_memory(m)\n    index.save_index(path)","handlingStrategy":"type-guard","validationCode":"if not path.with_suffix('.hnsw').exists():\n    # first run: build fresh\n    index = HNSWVectorIndex(dimension=embedder.dimension)\nelse:\n    await index.load_index(path)","typeGuard":"from pathlib import Path\ndef index_files_exist(base: Path) -> bool:\n    return base.with_suffix('.hnsw').exists() and base.with_suffix('.meta').exists()","tryCatchPattern":"try:\n    await index.load_index(path)\nexcept FileNotFoundError:\n    for m in memories:\n        await index.add_memory(m)\n    index.save_index(path)","preventionTips":["Remember load_index derives filenames via with_suffix('.hnsw') — avoid dots in the base path.","Treat a missing index as a normal first-run case, not an exception path."],"tags":["hnsw","persistence","file-not-found","load"],"backgroundTag":null,"analyzedSha":"322425c43bffde1ed0b64fecf3cf5951565dd82b","analyzedAt":"2026-08-15T01:03:05.481Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}