{"record":{"id":"305f866b4e5e0293","repo":"ruvnet/ruflo","slug":"hnsw-pattern-limit-reached-hnsw-max-safe-patter","errorCode":null,"errorMessage":"HNSW pattern limit reached (${HNSW_MAX_SAFE_PATTERNS}).","messagePattern":"HNSW pattern limit reached \\((.+?)\\)\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/ruvector/ruvllm-wasm.ts","lineNumber":173,"sourceCode":"  route: (query: Float32Array, k?: number) => HnswRouteResult[];\n  clear: () => void;\n  patternCount: () => number;\n  toJson: () => string;\n}> {\n  await initRuvllmWasm();\n  const mod = await import('@ruvector/ruvllm-wasm');\n\n  const router = new mod.HnswRouterWasm(config.dimensions, config.maxPatterns);\n  if (config.efSearch) {\n    router.setEfSearch(config.efSearch);\n  }\n\n  let count = 0;\n\n  return {\n    addPattern(pattern: HnswPattern): boolean {\n      if (count >= HNSW_MAX_SAFE_PATTERNS) {\n        throw new Error(\n          `HNSW pattern limit reached (${HNSW_MAX_SAFE_PATTERNS}).`\n        );\n      }\n      const metadataJson = JSON.stringify(pattern.metadata ?? {});\n      // addPattern requires 3 args: (embedding, name, metadata_json)\n      const ok = router.addPattern(pattern.embedding, pattern.name, metadataJson);\n      if (ok) count++;\n      return ok;\n    },\n    route(query: Float32Array, k = 3): HnswRouteResult[] {\n      const raw = router.route(query, k);\n      return Array.from(raw).map((r: any) => ({\n        name: r.name ?? r.pattern_name ?? '',\n        score: r.score ?? r.distance ?? 0,\n        metadata: r.metadata ? (typeof r.metadata === 'string' ? JSON.parse(r.metadata) : r.metadata) : undefined,\n      }));\n    },\n    clear(): void {","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/ruvnet/ruflo/blob/6b01dc5a687b26b3e218f796de45ec51f8fa9e8c/v3/@claude-flow/cli/src/ruvector/ruvllm-wasm.ts#L155-L191","documentation":"The WASM HNSW router caps stored patterns at HNSW_MAX_SAFE_PATTERNS (1024, the safe ceiling validated for @ruvector/ruvllm-wasm v2.0.2 which fixed connect_node ordering). addPattern() on the object returned by createHnswRouter() throws once the in-process counter reaches 1024, regardless of the maxPatterns value passed to the underlying constructor. This is a JS-side guard that fires before the WASM addPattern call, so partial writes do not occur.","triggerScenarios":"Calling addPattern(pattern) on the handle from createHnswRouter() after already successfully adding 1024 patterns (count is only incremented when router.addPattern returns truthy). Typical when bulk-loading a large embedding corpus or treating the HNSW router as a long-term memory store.","commonSituations":"Migration scripts that replay thousands of historical patterns into a fresh router; setting config.maxPatterns above 1024 expecting the cap to follow it (it does not — the JS guard is fixed at 1024); merging multiple intent catalogs without dedup; running long-lived daemon processes that accumulate patterns without calling clear().","solutions":["Reduce the pattern set to <=1024 by deduplicating or clustering before addPattern.","Call router.clear() and rebuild with a curated subset when the corpus exceeds 1024.","If you genuinely need more, shard across multiple HnswRouterWasm instances keyed by namespace and fan out route() queries.","Switch to the DiskANN backend (diskann-backend.ts) which targets larger-than-RAM pattern counts, instead of HNSW."],"exampleFix":"// before: blindly streaming all patterns\nfor (const p of allPatterns) router.addPattern(p); // throws at 1025th\n\n// after: cap and shard\nconst SHARD_SIZE = 1024;\nfor (let i = 0; i < allPatterns.length; i += SHARD_SIZE) {\n  const shard = shards[i / SHARD_SIZE] ??= await createHnswRouter(config);\n  for (const p of allPatterns.slice(i, i + SHARD_SIZE)) shard.addPattern(p);\n}","handlingStrategy":"validation","validationCode":"// Before calling addPattern, check the live count and the cap.\nimport { HNSW_MAX_SAFE_PATTERNS } from './ruvllm-wasm';\n\nfunction safeAdd(router, pattern) {\n  if (router.patternCount() >= HNSW_MAX_SAFE_PATTERNS) {\n    throw new Error(`Cannot add: cap is ${HNSW_MAX_SAFE_PATTERNS}; shard or clear first.`);\n  }\n  return router.addPattern(pattern);\n}","typeGuard":"function isHnswPattern(p): p is { embedding: Float32Array; name: string; metadata?: Record<string, unknown> } {\n  return p != null && p.embedding instanceof Float32Array && typeof p.name === 'string';\n}","tryCatchPattern":null,"preventionTips":["Track patternCount() before bulk inserts and stop or shard at HNSW_MAX_SAFE_PATTERNS.","Do not treat the HNSW router as unbounded long-term storage; use DiskANN for large corpora.","Read the exported HNSW_MAX_SAFE_PATTERNS constant rather than hardcoding 1024."],"tags":["hnsw","wasm","capacity-limit","ruvector","embeddings"],"backgroundTag":null,"analyzedSha":"6b01dc5a687b26b3e218f796de45ec51f8fa9e8c","analyzedAt":"2026-08-12T13:20:50.148Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}