ruvnet/ruflo · error
failed to load unified KRR
Error message
failed to load unified KRR
What it means
When building the routed engine, neural-router loads a trained-router artifact from cfg.bundledKrrPath (expected file seed-router.krr.json) via loadKrr(), which returns null when existsSync fails OR when reading/JSON.parse/TrainedRouter.fromJSON throws (all swallowed to null, neural-router.ts:438-454). A null unified artifact becomes this throw — the KRR (kernel routing rules) file is missing, unreadable, corrupt, or schema-incompatible.
Solutions
- Verify the artifact: check existsSync(cfg.bundledKrrPath) and dry-run JSON.parse on it in a REPL to surface the real cause
- Reinstall the package cleanly (rm -rf node_modules && npm install) so the bundled seed-router.krr.json is restored
- If bundledKrrPath was customized, point it at a known-good seed-router.krr.json matching your package version
- Fall back to the non-KRR routing path while regenerating or re-fetching the artifact
Example fix
// before
const router = tryCostOptimalRoute(...); // throws: failed to load unified KRR
// after (diagnose first)
import { existsSync, readFileSync } from 'node:fs';
const p = cfg.bundledKrrPath; // e.g. .../seed-router.krr.json
console.log('exists:', existsSync(p));
if (existsSync(p)) JSON.parse(readFileSync(p, 'utf8')); // surfaces parse/schema error
// then reinstall the package or fix bundledKrrPath before retrying Defensive patterns
Strategy: fallback
Validate before calling
import { existsSync, readFileSync } from 'node:fs';
function krrIsLoadable(path: string): boolean {
try { return existsSync(path) && !!JSON.parse(readFileSync(path, 'utf8')); }
catch { return false; }
} Type guard
function isLoadableKrrPath(path: string): boolean {
if (!existsSync(path)) return false;
try { JSON.parse(readFileSync(path, 'utf8')); return true; } catch { return false; }
} Try / catch
try {
router = buildRoutedEngine(cfg);
} catch (e) {
if (e instanceof Error && e.message === 'failed to load unified KRR') {
console.error(`KRR artifact missing/corrupt at ${cfg.bundledKrrPath} — using heuristic routing`);
router = heuristicRouter; // degrade, then fix the artifact out-of-band
} else throw e;
} Prevention
- After install, smoke-test that the bundled seed-router.krr.json exists and parses before first run
- If you override bundledKrrPath, validate the target in a startup check
- Mark the .krr.json asset as an external asset in bundler configs so it ships with dist
When it happens
Trigger: Package installed without the bundled .krr.json asset (files excluded from the npm tarball); cfg.bundledKrrPath overridden to a wrong or moved location; truncated/corrupt file from a partial download; version skew where TrainedRouter.fromJSON rejects the JSON layout of a newer artifact.
Common situations: Fresh installs or CI caches with pruned optional assets; bundlers (esbuild/webpack) that fail to copy JSON sidecars into dist; upgrading @claude-flow/cli or the MetaHarness writer so the old seed-router.krr.json no longer parses; custom deployment paths that drop data files.
Related errors
- archive did not contain the expected binary at its root
- AUTHENTICATION
- AUTHENTICATION
- AUTHENTICATION
- Config file already exists
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/b88eb40342925642.
Report an issue: GitHub.
Appendix: source
Thrown at v3/@claude-flow/cli/src/ruvector/neural-router.ts:457
if (!existsSync(path)) return null;
try {
const json = JSON.parse(readFileSync(path, 'utf8'));
const trained = mh.TrainedRouter.fromJSON(json);
const cands = json.candidates.map((c: { id: string; costPerMTok: number }) => ({ id: c.id, costPerMTok: c.costPerMTok }));
return {
route: (e: number[]) => {
const r = trained.route(e);
return { id: r.id, predictedQuality: r.predictedQuality, costPerMTok: r.costPerMTok, metBar: r.metBar };
},
predictAll: (e: number[]) => cands.map((c: { id: string; costPerMTok: number }) => ({
id: c.id, predictedQuality: trained.predict(c.id, e), costPerMTok: c.costPerMTok,
})).sort((a: { costPerMTok: number }, b: { costPerMTok: number }) => a.costPerMTok - b.costPerMTok),
};
} catch { return null; }
};
const unifiedRaw = loadKrr(cfg.bundledKrrPath);
if (!unifiedRaw) throw new Error('failed to load unified KRR');
const unified = wrapWithCalibrator(unifiedRaw, unifiedCalibrator);
// ADR-149 iter 16 — load per-bucket specialists if present. Each is a
// KRR fit only to its tier's rows (cheap → low.json, mid → med.json,
// strong → high.json). When tryCostOptimalRoute is called with a
// complexityBucket, the matching specialist is preferred over the
// unified router.
const bucketDir = cfg.bundledKrrPath.replace(/seed-router\.krr\.json$/, '');
const routerByBucket: Partial<Record<'low' | 'med' | 'high', PureRouter>> = {};
const loadedBuckets: string[] = [];
for (const bucket of ['low', 'med', 'high'] as const) {
const r = loadKrr(`${bucketDir}seed-router.krr.${bucket}.json`);
if (r) {
// iter 25 — prefer tier-specific calibrator for this bucket;
// fall back to the unified calibrator when no specialist exists.
routerByBucket[bucket] = wrapWithCalibrator(r, calibratorByBucket[bucket] ?? unifiedCalibrator);
loadedBuckets.push(bucket);
}View on GitHub (pinned to fa13ee4ad6)