ruvnet/ruflo · error
Duplicate route name
Error message
Duplicate route name: ${r.name} What it means
Thrown by loadPolicy() when two route entries in the routes file share the same name. Route names are the lookup key for routing decisions and telemetry, so duplicates are rejected during validation rather than silently overwritten — the message names the conflicting route.
Solutions
- Rename one of the duplicated routes so every name is unique (grep the file for the name from the error).
- Check for duplicates mechanically: jq 'group_by(.name) | map(select(length > 1)) | map(.[0].name)' routes.json.
- If the duplicate was intentional to express priority, instead use the ordering or scoring fields of a single route.
- Reload/restart so loadPolicy() revalidates the file.
Example fix
// before
[ { "name": "code", ... }, { "name": "code", ... } ]
// after
[ { "name": "code", ... }, { "name": "code-heavy", ... } ] Defensive patterns
Strategy: validation
Validate before calling
const names = routes.map((r) => r.name);
const dupes = names.filter((n, i) => names.indexOf(n) !== i);
if (dupes.length > 0) throw new Error(`duplicate route names: ${dupes.join(", ")}`); Type guard
function hasUniqueNames(routes: { name: string }[]): boolean {
return new Set(routes.map((r) => r.name)).size === routes.length;
} Prevention
- Lint the routes file for duplicate names in CI (jq group_by check).
- Generate route names programmatically (slugify) to avoid copy-paste collisions.
- Treat route names as stable identifiers: never reuse one for a different purpose.
When it happens
Trigger: The JSON array at LLM_ROUTER_ROUTES_PATH contains two objects with an identical non-empty name (e.g., copy-pasting a route and editing only the model).
Common situations: Duplicating an existing route to A/B test a different primary_model and forgetting to rename; merging two hand-maintained route files that both define a 'default' route.
Related errors
- Invalid route entry
- Routes config must be a flat array of routes
- agent must be an object
- bench must be an object
- bench.successCriteria must have ≥1 entry
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/743ce8f2afa3cc34.
Report an issue: GitHub.
Appendix: source
Thrown at ruflo/src/ruvocal/src/lib/server/router/policy.ts:21
import type { Route } from "./types";
let ROUTES: Route[] = [];
let loaded = false;
export async function loadPolicy(): Promise<Route[]> {
const path = config.LLM_ROUTER_ROUTES_PATH;
const text = await readFile(path, "utf8");
const arr = JSON.parse(text) as Route[];
if (!Array.isArray(arr)) {
throw new Error("Routes config must be a flat array of routes");
}
const seen = new Set<string>();
for (const r of arr) {
if (!r?.name || !r?.description || !r?.primary_model) {
throw new Error(`Invalid route entry: ${JSON.stringify(r)}`);
}
if (seen.has(r.name)) {
throw new Error(`Duplicate route name: ${r.name}`);
}
seen.add(r.name);
}
ROUTES = arr;
loaded = true;
return ROUTES;
}
export async function getRoutes(): Promise<Route[]> {
if (!loaded) await loadPolicy();
return ROUTES;
}
export function resolveRouteModels(
routeName: string,
routes: Route[],
fallbackModel: string
): { candidates: string[] } {View on GitHub (pinned to fa13ee4ad6)