{"record":{"id":"e96cb1e9831cdc87","repo":"ruvnet/ruflo","slug":"productquantizer-must-be-trained-before-decoding","errorCode":null,"errorMessage":"ProductQuantizer must be trained before decoding","messagePattern":"ProductQuantizer must be trained before decoding","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/plugins/src/integrations/ruvector/quantization.ts","lineNumber":900,"sourceCode":"    });\n  }\n\n  /**\n   * Implements IQuantizer interface - encodes vectors.\n   */\n  quantize(vectors: number[][]): Uint8Array[] {\n    return this.encode(vectors);\n  }\n\n  /**\n   * Decodes PQ codes back to approximate vectors.\n   *\n   * @param codes - PQ codes\n   * @returns Reconstructed vectors\n   */\n  decode(codes: Uint8Array[]): number[][] {\n    if (!this.isTrained) {\n      throw new Error('ProductQuantizer must be trained before decoding');\n    }\n\n    return codes.map((code) => {\n      const vec = new Array(this.dimensions);\n\n      for (let m = 0; m < this.numSubvectors; m++) {\n        const centroid = this.codebooks[m].centroids[code[m]];\n        const start = m * this.subvectorDim;\n        for (let d = 0; d < this.subvectorDim; d++) {\n          vec[start + d] = centroid[d];\n        }\n      }\n\n      return vec;\n    });\n  }\n\n  /**","sourceCodeStart":882,"sourceCodeEnd":918,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/plugins/src/integrations/ruvector/quantization.ts#L882-L918","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Call pq.train(trainingVectors) on the same instance before decode()","If using pretrained artifacts, load them via setCodebooks() or deserializeQuantizer() (both set isTrained) before decoding","Guard the call: only invoke decode() when the trained getter returns true","Persist quantizer state with serializeQuantizer after training and restore it in every process that decodes"],"exampleFix":"// before\nconst pq = new ProductQuantizer({ dimensions: 128, numSubvectors: 8 });\nconst vecs = pq.decode(codes); // throws\n\n// after\nconst pq = new ProductQuantizer({ dimensions: 128, numSubvectors: 8 });\npq.train(trainingVectors);\nconst vecs = pq.decode(codes);","handlingStrategy":"validation","validationCode":"if (!pq.trained) {\n  pq.train(trainingVectors);\n}\nconst vectors = pq.decode(codes);","typeGuard":"const isTrainedQuantizer = (q: IQuantizer): q is ProductQuantizer =>\n  q instanceof ProductQuantizer && q.trained;","tryCatchPattern":"try {\n  const vectors = pq.decode(codes);\n} catch (err) {\n  if (err instanceof Error && err.message.includes('must be trained')) {\n    pq.train(trainingVectors); // or load persisted codebooks\n  } else {\n    throw err;\n  }\n}","preventionTips":["Treat train() (or deserializeQuantizer) as part of construction: wrap quantizer creation in a factory that always returns a trained instance","Persist artifacts with serializeQuantizer and load them at startup in every process that decodes","Add a unit test asserting decode throws before train and succeeds after"],"tags":["quantization","product-quantizer","state-validation","vector-search"],"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-14T00:17:10.932Z"}