ruvnet/ruflo · error

ProductQuantizer must be trained before computing distances

Error message

ProductQuantizer must be trained before computing distances

What it means

Thrown by ProductQuantizer.computeDistances() (asymmetric distance computation, ADC) when isTrained is false. ADC builds per-subvector distance lookup tables from the learned codebook centroids; without training the codebooks do not exist and distances cannot be computed. The guard prevents meaningless NaN results.

Source

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

  dequantize(quantized: Uint8Array[]): number[][] {
    return this.decode(quantized);
  }

  /**
   * Computes asymmetric distances from a query to encoded vectors.
   *
   * Asymmetric distance computation (ADC):
   * - Query is NOT quantized (exact)
   * - Database vectors are quantized (codes)
   * - Distance is computed using lookup tables
   *
   * @param query - Query vector (float)
   * @param codes - Database PQ codes
   * @returns Array of distances
   */
  computeDistances(query: number[], codes: Uint8Array[]): number[] {
    if (!this.isTrained) {
      throw new Error('ProductQuantizer must be trained before computing distances');
    }

    // Build distance lookup tables
    const distanceTables = this.buildDistanceTables(query);

    // Compute distances using tables
    return codes.map((code) => {
      let distance = 0;
      for (let m = 0; m < this.numSubvectors; m++) {
        distance += distanceTables[m][code[m]];
      }
      return Math.sqrt(distance);
    });
  }

  /**
   * Builds distance lookup tables for asymmetric distance computation.
   */

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Train before searching: pq.train(trainingVectors) then computeDistances(query, codes)
  2. Load the persisted model: pq.setCodebooks(savedCodebooks) or deserializeQuantizer(blob) at service startup, then serve queries
  3. Check pq.trained at request time and fail fast with a clear 'quantizer not loaded' message before touching codes

Example fix

// before
const pq = new ProductQuantizer({ dimensions: 128, numSubvectors: 16 });
const dists = pq.computeDistances(query, dbCodes); // throws

// after
const pq = deserializeQuantizer(fs.readFileSync('pq-model.json', 'utf8'));
const dists = pq.computeDistances(query, dbCodes);
Defensive patterns

Strategy: validation

Validate before calling

if (!pq.trained) {
  throw new Error('Search unavailable: quantizer model not loaded');
}
const dists = pq.computeDistances(query, dbCodes);

Type guard

const isSearchReady = (q: ProductQuantizer): boolean => q.trained && q.trained;

Try / catch

try {
  return pq.computeDistances(query, codes);
} catch (err) {
  if (err instanceof Error && err.message.includes('must be trained')) {
    // fail the request loudly; retraining inline is usually wrong in serving paths
    throw new ServiceUnavailableError('vector index not warmed up');
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling computeDistances(query, codes) on a quantizer that was never trained — e.g. a search-time instance built per-request from options only, or one whose codebooks failed to load from storage.

Common situations: Serving path constructs a new ProductQuantizer for each query and forgets to restore persisted codebooks; training happened in a batch job but the deployed service never loads the artifact; unit test exercises search without the training fixture.

Related errors


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