ruvnet/ruflo · error
Embedding must be Float32Array of length
Error message
Embedding must be Float32Array of length ${this.dimension} What it means
Thrown by SemanticRouter.addIntentWithEmbeddings when any element of the embeddings array is not a Float32Array instance or its length differs from the dimension configured in the RouterConfig passed to the constructor. The router compares intent and query vectors component-by-component for cosine similarity, so wrong-type or wrong-length vectors are rejected up front instead of producing meaningless scores. Note the check is instanceof-based: a plain number[] (e.g. after JSON round-trip) fails even if the length is correct.
Solutions
- Rehydrate every vector before registering: embeddings.map(v => v instanceof Float32Array ? v : Float32Array.from(v))
- Confirm each vector's length equals the dimension in your RouterConfig; regenerate embeddings if the embedding model changed
- If you genuinely have mixed dimensions, use one SemanticRouter instance per dimension instead of one router for all
Example fix
// before
const saved = JSON.parse(fs.readFileSync('intents.json', 'utf8'));
router.addIntentWithEmbeddings('greet', saved.embeddings); // plain arrays -> throws
// after
const saved = JSON.parse(fs.readFileSync('intents.json', 'utf8'));
const vecs = saved.embeddings.map((v: number[]) => Float32Array.from(v));
// assert lengths match the configured dimension
if (!vecs.every(v => v.length === routerDim)) throw new Error('stale embeddings; regenerate');
router.addIntentWithEmbeddings('greet', vecs); Defensive patterns
Strategy: type-guard
Validate before calling
const DIM = 384; // must equal RouterConfig.dimension
const valid = intentEmbeddings.every(e => e instanceof Float32Array && e.length === DIM);
if (!valid) intentEmbeddings = intentEmbeddings.map(e => Float32Array.from(e as number[]));
if (!intentEmbeddings.every(e => e.length === DIM)) throw new TypeError('embeddings have wrong dimension — regenerate with the current model'); Type guard
function isTrainedEmbedding(v: unknown, dim: number): v is Float32Array {
return v instanceof Float32Array && v.length === dim;
} Prevention
- Derive RouterConfig.dimension from the embedding model's declared output size, never a hardcoded literal in two places
- Always rehydrate persisted embeddings with Float32Array.from() after JSON/disk round-trips
- Add a startup assertion that every intent embedding length matches the configured dimension
When it happens
Trigger: Calling router.addIntentWithEmbeddings(name, embeddings) where embeddings came from JSON.parse (plain Array), where vectors were produced by a different embedding model whose output dimension differs from config.dimension, or where one element of the array is empty/truncated.
Common situations: Persisting intent embeddings to disk as JSON and reloading them (Float32Array serializes to a normal array), swapping embedding providers (e.g. 1536-dim OpenAI text-embedding vs 384-dim MiniLM) without updating the router's dimension, mixing example vectors from an old training run with a new router config.
Related errors
- each record requires a non-empty numeric vector
- Invalid embedding model name
- Invalid embedding value at index
- Must provide name and embeddings array
- SemanticRouter requires a dimension in config
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/4e3f98a110f03b73.
Report an issue: GitHub.
Appendix: source
Thrown at v3/@claude-flow/cli/src/ruvector/semantic-router.ts:62
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 embeddings
for (const emb of embeddings) {
if (!(emb instanceof Float32Array) || emb.length !== this.dimension) {
throw new Error(`Embedding must be Float32Array of length ${this.dimension}`);
}
}
// Normalize embeddings for cosine similarity
const normalizedEmbeddings = embeddings.map(emb => this.normalize(emb));
this.intents.set(name, {
name,
embeddings: normalizedEmbeddings,
metadata,
});
this.totalVectors += embeddings.length;
}
/**
* Route a query using a pre-computed embedding
*/
routeWithEmbedding(embedding: Float32Array, k = 5): RouteResult[] {View on GitHub (pinned to fa13ee4ad6)