{"record":{"id":"0fd06bbb8aaf1aa2","repo":"ruvnet/ruflo","slug":"productquantizer-must-be-trained-before-computing","errorCode":null,"errorMessage":"ProductQuantizer must be trained before computing distances","messagePattern":"ProductQuantizer must be trained before computing distances","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/plugins/src/integrations/ruvector/quantization.ts","lineNumber":939,"sourceCode":"  dequantize(quantized: Uint8Array[]): number[][] {\n    return this.decode(quantized);\n  }\n\n  /**\n   * Computes asymmetric distances from a query to encoded vectors.\n   *\n   * Asymmetric distance computation (ADC):\n   * - Query is NOT quantized (exact)\n   * - Database vectors are quantized (codes)\n   * - Distance is computed using lookup tables\n   *\n   * @param query - Query vector (float)\n   * @param codes - Database PQ codes\n   * @returns Array of distances\n   */\n  computeDistances(query: number[], codes: Uint8Array[]): number[] {\n    if (!this.isTrained) {\n      throw new Error('ProductQuantizer must be trained before computing distances');\n    }\n\n    // Build distance lookup tables\n    const distanceTables = this.buildDistanceTables(query);\n\n    // Compute distances using tables\n    return codes.map((code) => {\n      let distance = 0;\n      for (let m = 0; m < this.numSubvectors; m++) {\n        distance += distanceTables[m][code[m]];\n      }\n      return Math.sqrt(distance);\n    });\n  }\n\n  /**\n   * Builds distance lookup tables for asymmetric distance computation.\n   */","sourceCodeStart":921,"sourceCodeEnd":957,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/plugins/src/integrations/ruvector/quantization.ts#L921-L957","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Train before searching: pq.train(trainingVectors) then computeDistances(query, codes)","Load the persisted model: pq.setCodebooks(savedCodebooks) or deserializeQuantizer(blob) at service startup, then serve queries","Check pq.trained at request time and fail fast with a clear 'quantizer not loaded' message before touching codes"],"exampleFix":"// before\nconst pq = new ProductQuantizer({ dimensions: 128, numSubvectors: 16 });\nconst dists = pq.computeDistances(query, dbCodes); // throws\n\n// after\nconst pq = deserializeQuantizer(fs.readFileSync('pq-model.json', 'utf8'));\nconst dists = pq.computeDistances(query, dbCodes);","handlingStrategy":"validation","validationCode":"if (!pq.trained) {\n  throw new Error('Search unavailable: quantizer model not loaded');\n}\nconst dists = pq.computeDistances(query, dbCodes);","typeGuard":"const isSearchReady = (q: ProductQuantizer): boolean => q.trained && q.trained;","tryCatchPattern":"try {\n  return pq.computeDistances(query, codes);\n} catch (err) {\n  if (err instanceof Error && err.message.includes('must be trained')) {\n    // fail the request loudly; retraining inline is usually wrong in serving paths\n    throw new ServiceUnavailableError('vector index not warmed up');\n  }\n  throw err;\n}","preventionTips":["Load pretrained codebooks during service bootstrap and assert pq.trained before accepting traffic","Expose trained state in readiness probes so unwarmed replicas are skipped","Keep one shared trained instance rather than constructing per request"],"tags":["quantization","product-quantizer","anns-search","state-validation"],"backgroundTag":"model-not-fitted","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}