ruvnet/ruflo · error
Routes config must be a flat array of routes
Error message
Routes config must be a flat array of routes
What it means
Thrown by loadPolicy() in the router policy loader (policy.ts). The routes file pointed to by LLM_ROUTER_ROUTES_PATH must be a top-level JSON array of route objects; after JSON.parse succeeds, a non-array top level (object, string, number) means the file format is wrong and the router cannot load its routing table.
Solutions
- Open the file at $LLM_ROUTER_ROUTES_PATH and make the root a flat array: [{ name, description, primary_model, ... }, ...].
- If you keep an envelope in source, unwrap it when writing the file or point LLM_ROUTER_ROUTES_PATH at a generated flat file.
- Validate with: node -e "console.log(Array.isArray(require('./routes.json')))" or jq 'type' routes.json (should print 'array').
- Restart the server so loadPolicy() re-reads the corrected file.
Example fix
// routes.json (before)
{ "routes": [ { "name": "code", "description": "...", "primary_model": "..." } ] }
// routes.json (after)
[ { "name": "code", "description": "...", "primary_model": "..." } ] Defensive patterns
Strategy: validation
Validate before calling
import { readFileSync } from "node:fs";
const raw = JSON.parse(readFileSync(process.env.LLM_ROUTER_ROUTES_PATH!, "utf8"));
if (!Array.isArray(raw)) {
throw new Error("routes file root must be an array");
} Type guard
function isRouteArray(v: unknown): v is unknown[] {
return Array.isArray(v);
} Prevention
- Validate the routes file in CI with a JSON-schema or unit test before deploy.
- Keep a canonical example routes file and diff against it on change.
- Prefer generating the file from typed code so its shape cannot drift.
When it happens
Trigger: LLM_ROUTER_ROUTES_PATH points at a JSON file whose root is an object — commonly { "routes": [...] } — or at the wrong file entirely (a config object, a single route, or output from another tool).
Common situations: Author wrapping the array for readability; examples/docs showing an envelope object; editing the wrong path (LLM_ROUTER_ROUTES_PATH still pointing at a stale file).
Related errors
- Invalid route entry
- Duplicate route name
- Router multimodal is enabled but…
- agent must be an object
- bench must be an object
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/b647b3e2c2241a1f.
Report an issue: GitHub.
Appendix: source
Thrown at ruflo/src/ruvocal/src/lib/server/router/policy.ts:13
import { readFile } from "node:fs/promises";
import { config } from "$lib/server/config";
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();View on GitHub (pinned to fa13ee4ad6)