ruvnet/ruflo · error
SemanticRouter requires a dimension in config
Error message
SemanticRouter requires a dimension in config
What it means
The SemanticRouter constructor requires config.dimension to be a number (it sizes every embedding it will store — addIntentWithEmbeddings later enforces Float32Array of exactly this length). A missing, undefined, or non-numeric dimension throws immediately at construction.
Solutions
- Pass dimension matching your embedding model: 384 (all-MiniLM-L6-v2), 768 (bge-base), 1536 (text-embedding-3-small), 3072 (text-embedding-3-large), etc.
- Parse/validate config at load time: Number.isFinite(config.dimension) before constructing
- Centralize the dimension in one constant shared by the embedder and the router so they cannot diverge
- If config is dynamic, default it explicitly (e.g., ?? 384) rather than leaving it undefined
Example fix
// before
const router = new SemanticRouter({ metric: 'cosine' } as any); // throws: requires a dimension
// after
const DIM = 384; // all-MiniLM-L6-v2
const router = new SemanticRouter({ dimension: DIM, metric: 'cosine' }); Defensive patterns
Strategy: validation
Validate before calling
function makeRouter(cfg: unknown) {
const dimension = Number((cfg as any)?.dimension);
if (!Number.isFinite(dimension) || dimension <= 0) {
throw new Error('SemanticRouter config needs numeric dimension (e.g., 384 for MiniLM)');
}
return new SemanticRouter({ dimension, metric: 'cosine' });
} Type guard
function hasNumericDimension(cfg: unknown): cfg is { dimension: number } {
return !!cfg && typeof (cfg as any).dimension === 'number' && Number.isFinite((cfg as any).dimension);
} Try / catch
try {
router = new SemanticRouter(config as any);
} catch (e) {
if (e instanceof Error && e.message === 'SemanticRouter requires a dimension in config') {
router = new SemanticRouter({ dimension: DEFAULT_DIMENSION }); // fail loud in dev, default in prod
} else throw e;
} Prevention
- Parse config with a schema (zod) that requires dimension: number before it reaches the constructor
- Share one DIMENSION constant between the embedder and the router so they always match
- Env/config values arrive as strings — Number() them at load time, never at use time
When it happens
Trigger: new SemanticRouter({} as any) or new SemanticRouter({metric:'cosine'}) with dimension forgotten; dimension passed as a string ('384') from env/config parsing; config objects built conditionally where the dimension field is only set on one branch; new SemanticRouter(null).
Common situations: Config loaded from JSON/env where everything arrives as strings; switching embedding models and deleting the dimension field while refactoring; partial config objects satisfying TypeScript via casts; copying router setup code that assumed a default dimension (there is none).
Understand the failure class
Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.
Related errors
- Agent config must include id, name, and type
- Embedding must be Float32Array of length
- Must provide name and embeddings array
- dropoutRate must be between 0 and 1
- each record requires a non-empty numeric vector
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/7ae72da97f4d9bd0.
Report an issue: GitHub.
Appendix: source
Thrown at v3/@claude-flow/cli/src/ruvector/semantic-router.ts:41
dimension: number;
metric?: 'cosine' | 'euclidean' | 'dotProduct';
}
interface StoredIntent {
name: string;
embeddings: Float32Array[];
metadata: Record<string, unknown>;
}
export class SemanticRouter {
private dimension: number;
private metric: 'cosine' | 'euclidean' | 'dotProduct';
private intents: Map<string, StoredIntent> = new Map();
private totalVectors = 0;
constructor(config: RouterConfig) {
if (!config || typeof config.dimension !== 'number') {
throw new Error('SemanticRouter requires a dimension in config');
}
this.dimension = config.dimension;
this.metric = config.metric ?? 'cosine';
}
/**
* Add an intent with pre-computed embeddings
*/
addIntentWithEmbeddings(
name: string,
embeddings: Float32Array[],
metadata: Record<string, unknown> = {}
): void {
if (!name || !Array.isArray(embeddings)) {
throw new Error('Must provide name and embeddings array');
}
// Validate embeddingsView on GitHub (pinned to fa13ee4ad6)