{"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":null,"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/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/cli/src/ruvector/ruvllm-wasm.ts#L155-L191","documentation":"The HNSW router wrapper enforces a hard safety cap of HNSW_MAX_SAFE_PATTERNS = 1024 patterns (exported at ruvllm-wasm.ts:145), independent of the maxPatterns you pass to the constructor. addPattern() throws once the count of successfully added patterns reaches 1024; the cap exists to bound wasm-side memory since HNSW index memory grows with pattern count.","triggerScenarios":"Bulk-loading more than 1024 embeddings into one router; accumulating patterns across a long-running process without eviction; replaying an event log into the index on every restart, incrementing past the cap; concurrent producers adding patterns between your count checks.","commonSituations":"Rebuilding a routing index from history on boot; memory/knowledge ingestion pipelines with no dedupe; multi-tenant designs funneling all tenants' patterns into a single router.","solutions":["Prune before adding: evict the oldest or lowest-value patterns to stay under 1024","Shard: partition patterns across multiple HNSW routers (by tenant, topic, or bucket) and merge route() results","Dedupe by pattern.name before re-adding on restart so counts do not grow monotonically","Track the count yourself and stop or rotate before hitting the cap (the wrapper exposes no count getter)"],"exampleFix":"// before\nfor (const p of allPatterns) router.addPattern(p); // throws at pattern #1025\n// after\nimport { HNSW_MAX_SAFE_PATTERNS } from './ruvllm-wasm';\nlet added = 0;\nfor (const p of allPatterns) {\n  if (added >= HNSW_MAX_SAFE_PATTERNS) throw new Error('pattern budget exhausted — shard the router');\n  if (router.addPattern(p)) added++;\n}","handlingStrategy":"validation","validationCode":"import { HNSW_MAX_SAFE_PATTERNS } from './ruvllm-wasm';\nfunction budgetRemaining(added: number): number {\n  return HNSW_MAX_SAFE_PATTERNS - added; // check before every batch add","typeGuard":"const hasPatternBudget = (added: number): boolean => added < HNSW_MAX_SAFE_PATTERNS;","tryCatchPattern":"try {\n  ok = router.addPattern(p);\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('HNSW pattern limit reached')) {\n    evictOldestPattern(); ok = router.addPattern(p); // make room, retry once\n  } else throw e;\n}","preventionTips":["Track your own add count — the wrapper exposes no getter and the cap (1024) is hard","Dedupe by pattern.name when replaying history so counts do not grow per restart","Shard large pattern sets across multiple routers instead of fighting the cap"],"tags":["wasm","hnsw","vector-index","capacity-limit","memory"],"backgroundTag":"capacity-limit-exceeded","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}