ruvnet/ruflo · error · Error
HNSW pattern limit reached (${HNSW_MAX_SAFE_PATTERNS}).
Error message
HNSW pattern limit reached (${HNSW_MAX_SAFE_PATTERNS}). What it means
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.
Source
Thrown at v3/@claude-flow/cli/src/ruvector/ruvllm-wasm.ts:173
route: (query: Float32Array, k?: number) => HnswRouteResult[];
clear: () => void;
patternCount: () => number;
toJson: () => string;
}> {
await initRuvllmWasm();
const mod = await import('@ruvector/ruvllm-wasm');
const router = new mod.HnswRouterWasm(config.dimensions, config.maxPatterns);
if (config.efSearch) {
router.setEfSearch(config.efSearch);
}
let count = 0;
return {
addPattern(pattern: HnswPattern): boolean {
if (count >= HNSW_MAX_SAFE_PATTERNS) {
throw new Error(
`HNSW pattern limit reached (${HNSW_MAX_SAFE_PATTERNS}).`
);
}
const metadataJson = JSON.stringify(pattern.metadata ?? {});
// addPattern requires 3 args: (embedding, name, metadata_json)
const ok = router.addPattern(pattern.embedding, pattern.name, metadataJson);
if (ok) count++;
return ok;
},
route(query: Float32Array, k = 3): HnswRouteResult[] {
const raw = router.route(query, k);
return Array.from(raw).map((r: any) => ({
name: r.name ?? r.pattern_name ?? '',
score: r.score ?? r.distance ?? 0,
metadata: r.metadata ? (typeof r.metadata === 'string' ? JSON.parse(r.metadata) : r.metadata) : undefined,
}));
},
clear(): void {View on GitHub (pinned to 6b01dc5a68)
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.
Example fix
// before: blindly streaming all patterns
for (const p of allPatterns) router.addPattern(p); // throws at 1025th
// after: cap and shard
const SHARD_SIZE = 1024;
for (let i = 0; i < allPatterns.length; i += SHARD_SIZE) {
const shard = shards[i / SHARD_SIZE] ??= await createHnswRouter(config);
for (const p of allPatterns.slice(i, i + SHARD_SIZE)) shard.addPattern(p);
} Defensive patterns
Strategy: validation
Validate before calling
// Before calling addPattern, check the live count and the cap.
import { HNSW_MAX_SAFE_PATTERNS } from './ruvllm-wasm';
function safeAdd(router, pattern) {
if (router.patternCount() >= HNSW_MAX_SAFE_PATTERNS) {
throw new Error(`Cannot add: cap is ${HNSW_MAX_SAFE_PATTERNS}; shard or clear first.`);
}
return router.addPattern(pattern);
} Type guard
function isHnswPattern(p): p is { embedding: Float32Array; name: string; metadata?: Record<string, unknown> } {
return p != null && p.embedding instanceof Float32Array && typeof p.name === 'string';
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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().
Related errors
- Invalid embedding value at index ${i}: expected finite numbe
- Failed to load WASM module
- MCP initialization failed: ${initResponse.error.message}
- Template not found: ${id}
- Template not found: ${id}
AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12).
Data as JSON: /api/errors/305f866b4e5e0293.
Report an issue: GitHub.