{"record":{"id":"cff7603544ed2b2e","repo":"ruvnet/ruflo","slug":"dimensions-options-dimensions-must-be-divisib","errorCode":null,"errorMessage":"Dimensions (${options.dimensions}) must be divisible by numSubvectors (${options.numSubvectors})","messagePattern":"Dimensions \\((.+?)\\) must be divisible by numSubvectors \\((.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/plugins/src/integrations/ruvector/quantization.ts","lineNumber":694,"sourceCode":"  readonly dimensions: number;\n  readonly numSubvectors: number;\n  readonly numCentroids: number;\n  readonly subvectorDim: number;\n\n  protected codebooks: Codebook[] = [];\n  protected isTrained: boolean = false;\n  protected readonly maxIterations: number;\n  protected readonly tolerance: number;\n  protected readonly rng: () => number;\n\n  constructor(options: ProductQuantizationOptions) {\n    this.dimensions = options.dimensions;\n    this.numSubvectors = options.numSubvectors;\n    this.numCentroids = options.numCentroids;\n\n    // Validate dimensions divisibility\n    if (options.dimensions % options.numSubvectors !== 0) {\n      throw new Error(\n        `Dimensions (${options.dimensions}) must be divisible by numSubvectors (${options.numSubvectors})`\n      );\n    }\n\n    this.subvectorDim = options.dimensions / options.numSubvectors;\n    this.maxIterations = options.maxIterations ?? 100;\n    this.tolerance = options.tolerance ?? 1e-6;\n    this.rng = createRng(options.seed ?? 42);\n  }\n\n  /**\n   * Trains codebooks from training data using k-means clustering.\n   *\n   * @param vectors - Training vectors\n   */\n  async train(vectors: number[][]): Promise<void> {\n    if (vectors.length < this.numCentroids) {\n      throw new Error(","sourceCodeStart":676,"sourceCodeEnd":712,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/plugins/src/integrations/ruvector/quantization.ts#L676-L712","documentation":"ProductQuantizer's constructor (quantization.ts:694) requires dimensions % numSubvectors === 0 because each subvector codebook covers an equal slice of dimensions (subvectorDim = dimensions / numSubvectors). Any remainder makes slicing ambiguous, so construction fails immediately with both values in the message.","triggerScenarios":"new ProductQuantizer({ dimensions: 1536, numSubvectors: 100 }) — 1536 % 100 != 0; reusing an 8-subvector config with a 312-dim embedding model; odd dimensions like 127 or 200 with non-divisor M.","commonSituations":"Switching embedding providers (1536 for ada-002, 768/1024 for others) without adjusting numSubvectors; copying the default M=8 into configs for models with dimensions not divisible by 8; hand-tuned M values that don't factor the dimension.","solutions":["Pick numSubvectors that divides dimensions exactly (e.g. 1536: 8, 16, 24, 32, 48; 768: 8, 12, 16, 24)","Compute it: const m = largestPowerOfTwoDividing(dimensions) or gcd-based choice","Validate the pair in config loading: assert dimensions % numSubvectors === 0 with both values in the error"],"exampleFix":"// before\nconst pq = new ProductQuantizer({ dimensions: 1536, numSubvectors: 100, numCentroids: 256 }); // throws\n\n// after\nconst dims = 1536;\nconst numSubvectors = 16; // 1536 / 16 = 96-dim subvectors\nconst pq = new ProductQuantizer({ dimensions: dims, numSubvectors, numCentroids: 256 });","handlingStrategy":"validation","validationCode":"function assertPQOptions(dimensions: number, numSubvectors: number) {\n  if (!Number.isInteger(dimensions) || dimensions <= 0) throw new TypeError(`bad dimensions ${dimensions}`);\n  if (!Number.isInteger(numSubvectors) || numSubvectors <= 0) throw new TypeError(`bad numSubvectors ${numSubvectors}`);\n  if (dimensions % numSubvectors !== 0) {\n    throw new RangeError(`dimensions ${dimensions} not divisible by numSubvectors ${numSubvectors}`);\n  }\n}\nassertPQOptions(cfg.dimensions, cfg.numSubvectors);\nconst pq = new ProductQuantizer(cfg);","typeGuard":"function isValidPQConfig(cfg: { dimensions: number; numSubvectors: number }): boolean {\n  return cfg.dimensions > 0 && cfg.numSubvectors > 0 && cfg.dimensions % cfg.numSubvectors === 0;\n}","tryCatchPattern":"try {\n  pq = new ProductQuantizer(cfg);\n} catch (err) {\n  if (err instanceof Error && err.message.includes('must be divisible by numSubvectors')) {\n    cfg = { ...cfg, numSubvectors: 8 }; // retry with a standard divisor\n    pq = new ProductQuantizer(cfg);\n  } else throw err;\n}","preventionTips":["Derive numSubvectors from the embedding model's dimension (1536 -> 16/24/48; 768 -> 8/12/16/24)","Re-validate the pair whenever the embedding provider changes","Encode the constraint in config schemas (multipleOf) so it fails at validation time"],"tags":["quantization","product-quantization","dimension-mismatch","configuration"],"backgroundTag":"dimension-mismatch","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"}