ruvnet/ruflo · error

Cannot learn thresholds from empty samples

Error message

Cannot learn thresholds from empty samples

What it means

BinaryQuantizer.learnThresholds() (quantization.ts:500) computes a per-dimension median threshold from training vectors to decide the 0/1 bit each dimension encodes. Median computation requires at least one value per dimension, so an empty samples array throws. The quantizer otherwise falls back to zero thresholds.

Source

Thrown at v3/@claude-flow/plugins/src/integrations/ruvector/quantization.ts:500

  private readonly bytesPerVector: number;

  constructor(options: BinaryQuantizationOptions) {
    this.dimensions = options.dimensions;
    this.threshold = options.threshold ?? 0;
    this.learnedThresholds = options.learnedThresholds ?? null;

    // Calculate bytes needed (ceil(dimensions / 8))
    this.bytesPerVector = Math.ceil(this.dimensions / 8);
  }

  /**
   * Learns optimal thresholds per dimension from training data.
   *
   * @param samples - Training vectors
   */
  learnThresholds(samples: number[][]): void {
    if (samples.length === 0) {
      throw new Error('Cannot learn thresholds from empty samples');
    }

    // Compute median per dimension as threshold
    this.learnedThresholds = new Array(this.dimensions);

    for (let d = 0; d < this.dimensions; d++) {
      const values = samples.map(s => s[d]).sort((a, b) => a - b);
      const mid = Math.floor(values.length / 2);
      this.learnedThresholds[d] = values.length % 2 === 0
        ? (values[mid - 1] + values[mid]) / 2
        : values[mid];
    }
  }

  /**
   * Quantizes float32 vectors to binary.
   *
   * @param vectors - Input vectors

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Guard the call: only invoke learnThresholds when samples.length > 0
  2. Fall back to the default zero thresholds (skip learning) when data is missing
  3. Fail the job earlier with a clear message if training data is a hard requirement

Example fix

// before
bq.learnThresholds(trainSet); // throws if trainSet is []

// after
if (trainSet.length > 0) {
  bq.learnThresholds(trainSet);
} else {
  bq.learnThresholds([new Array(bq.dimensions).fill(0)]); // neutral threshold until data arrives
}
Defensive patterns

Strategy: validation

Validate before calling

if (samples.length === 0) {
  throw new Error('learnThresholds requires at least one training vector');
}
bq.learnThresholds(samples);

Type guard

function isNonEmptySamples(v: number[][]): v is [number[], ...number[][]] {
  return Array.isArray(v) && v.length > 0;
}

Try / catch

try {
  bq.learnThresholds(samples);
} catch (err) {
  if (err instanceof Error && err.message === 'Cannot learn thresholds from empty samples') {
    bq.learnThresholds([new Array(dim).fill(0)]); // neutral thresholds until real data
  } else throw err;
}

Prevention

When it happens

Trigger: learnThresholds([]) when the training fetch returned no rows; slicing a dataset with .slice(0, 0) or an empty feature group; test fixtures that forgot to include vectors.

Common situations: First-run pipelines before any data exists; ETL filters (tenant, date range) producing empty result sets; unit tests with stubbed empty datasets.

Related errors


AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18). Data as JSON: /api/errors/19322f319085db44. Report an issue: GitHub.