ruvnet/ruflo · error · Error

Invalid embedding value at index ${i}: expected finite numbe

Error message

Invalid embedding value at index ${i}: expected finite number, got ${typeof embedding[i]}

What it means

Thrown by formatEmbedding() when any element of the embedding array is not a finite number (NaN, Infinity, a string, null, undefined). This guard exists primarily to prevent SQL injection and data corruption via crafted embedding JSON passed into the ruvector() PostgreSQL cast — every value is interpolated into the literal vector string, so non-numeric content would break out of the numeric context.

Source

Thrown at v3/@claude-flow/cli/src/commands/ruvector/import.ts:52

 */
interface ImportStats {
  total: number;
  imported: number;
  skipped: number;
  errors: number;
  withEmbeddings: number;
  byNamespace: Record<string, number>;
}

/**
 * Format a ruvector embedding array for PostgreSQL
 * Validates each element is a finite number to prevent SQL injection via crafted arrays.
 */
function formatEmbedding(embedding: number[], dimensions: number = 384): string {
  // Validate every element is a finite number (prevents SQL injection via crafted JSON)
  for (let i = 0; i < embedding.length; i++) {
    if (typeof embedding[i] !== 'number' || !Number.isFinite(embedding[i])) {
      throw new Error(`Invalid embedding value at index ${i}: expected finite number, got ${typeof embedding[i]}`);
    }
  }

  // Ensure correct dimensions by padding or truncating
  const padded = [...embedding];
  while (padded.length < dimensions) {
    padded.push(0);
  }
  if (padded.length > dimensions) {
    padded.length = dimensions;
  }
  return `'[${padded.join(',')}]'::ruvector(${dimensions})`;
}

/**
 * Escape string for PostgreSQL
 */
function escapeString(str: string): string {

View on GitHub (pinned to 6b01dc5a68)

Solutions

  1. Sanitize the array before import: replace non-finite values or drop the row entirely.
  2. Inspect the offending index reported in the message to find which record is malformed.
  3. Validate at the producer: ensure the embedding pipeline only emits finite numbers.

Example fix

// before
const emb = [0.1, NaN, 0.3];
formatEmbedding(emb);
// after
const emb = [0.1, NaN, 0.3];
if (!emb.every(v => typeof v === 'number' && Number.isFinite(v))) {
  throw new Error('embedding has non-finite values');
}
formatEmbedding(emb);
Defensive patterns

Strategy: type-guard

Validate before calling

function isFiniteNumberArray(v: unknown): v is number[] {
  return Array.isArray(v) && v.every(x => typeof x === 'number' && Number.isFinite(x));
}
// before importing:
if (!isFiniteNumberArray(record.embedding)) {
  throw new Error(`record ${record.id} has non-finite embedding values`);
}

Type guard

const isFiniteNumber = (v: unknown): v is number =>
  typeof v === 'number' && Number.isFinite(v);
const isFiniteNumberArray = (v: unknown): v is number[] =>
  Array.isArray(v) && v.every(isFiniteNumber);

Try / catch

try {
  formatEmbedding(emb, dims);
} catch (e) {
  const msg = e instanceof Error ? e.message : String(e);
  if (msg.startsWith('Invalid embedding value')) {
    // drop the row or sanitize, then continue
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: Importing an embedding payload that contains NaN/Infinity (e.g. from JSON that legitimately cannot carry those but which was produced by a buggy model client emitting strings), nulls where numbers belong, or a partially-decoded buffer.

Common situations: Model client emitting 'NaN'/'Infinity' as strings, a downstream pipeline leaving null placeholders for failed inferences, mixed-type arrays from a sloppy export, or unit tests feeding [1,'2',3].

Related errors


AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12). Data as JSON: /api/errors/43e182666297a5ca. Report an issue: GitHub.