ruvnet/ruflo · error

ProductQuantizer must be trained before decoding

Error message

ProductQuantizer must be trained before decoding

What it means

Thrown by ProductQuantizer.decode() when the quantizer's isTrained flag is false. Decoding PQ codes requires learned codebooks (this.codebooks[m].centroids); without training they are undefined, so decode() would either crash on undefined centroid access or return garbage. The library refuses to decode rather than emit corrupt reconstructed vectors.

Source

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

    });
  }

  /**
   * Implements IQuantizer interface - encodes vectors.
   */
  quantize(vectors: number[][]): Uint8Array[] {
    return this.encode(vectors);
  }

  /**
   * Decodes PQ codes back to approximate vectors.
   *
   * @param codes - PQ codes
   * @returns Reconstructed vectors
   */
  decode(codes: Uint8Array[]): number[][] {
    if (!this.isTrained) {
      throw new Error('ProductQuantizer must be trained before decoding');
    }

    return codes.map((code) => {
      const vec = new Array(this.dimensions);

      for (let m = 0; m < this.numSubvectors; m++) {
        const centroid = this.codebooks[m].centroids[code[m]];
        const start = m * this.subvectorDim;
        for (let d = 0; d < this.subvectorDim; d++) {
          vec[start + d] = centroid[d];
        }
      }

      return vec;
    });
  }

  /**

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Call pq.train(trainingVectors) on the same instance before decode()
  2. If using pretrained artifacts, load them via setCodebooks() or deserializeQuantizer() (both set isTrained) before decoding
  3. Guard the call: only invoke decode() when the trained getter returns true
  4. Persist quantizer state with serializeQuantizer after training and restore it in every process that decodes

Example fix

// before
const pq = new ProductQuantizer({ dimensions: 128, numSubvectors: 8 });
const vecs = pq.decode(codes); // throws

// after
const pq = new ProductQuantizer({ dimensions: 128, numSubvectors: 8 });
pq.train(trainingVectors);
const vecs = pq.decode(codes);
Defensive patterns

Strategy: validation

Validate before calling

if (!pq.trained) {
  pq.train(trainingVectors);
}
const vectors = pq.decode(codes);

Type guard

const isTrainedQuantizer = (q: IQuantizer): q is ProductQuantizer =>
  q instanceof ProductQuantizer && q.trained;

Try / catch

try {
  const vectors = pq.decode(codes);
} catch (err) {
  if (err instanceof Error && err.message.includes('must be trained')) {
    pq.train(trainingVectors); // or load persisted codebooks
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: Constructing a ProductQuantizer and calling decode(codes) before calling train(trainingVectors). Also calling decode on a fresh instance after a failed/partial deserializeQuantizer that never reached setCodebooks (which sets isTrained = true).

Common situations: Test code that quantizes with a shared helper but decodes with a newly constructed quantizer; splitting the training and query phases across processes and forgetting to load the persisted codebooks in the query process; assuming the constructor or quantize() trains implicitly.

Related errors


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