ruvnet/ruflo · error

Expected ${this.numSubvectors} codebooks, got ${codebooks.le

Error message

Expected ${this.numSubvectors} codebooks, got ${codebooks.length}

What it means

Thrown by ProductQuantizer.setCodebooks() when the supplied array length differs from the quantizer's numSubvectors. Each PQ code byte m indexes codebooks[m], so the codebook count must exactly match M. This is a shape check on pretrained model data and typically means the saved artifact was trained with a different configuration than the current instance.

Source

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

    return `${ratio.toFixed(1)}x`;
  }

  /**
   * Gets the trained codebooks.
   */
  getCodebooks(): Codebook[] {
    return this.codebooks.map(cb => ({
      centroids: cb.centroids.map(c => [...c]),
      counts: [...cb.counts],
    }));
  }

  /**
   * Sets codebooks directly (for loading pretrained).
   */
  setCodebooks(codebooks: Codebook[]): void {
    if (codebooks.length !== this.numSubvectors) {
      throw new Error(`Expected ${this.numSubvectors} codebooks, got ${codebooks.length}`);
    }
    this.codebooks = codebooks;
    this.isTrained = true;
  }

  /**
   * Checks if the quantizer is trained.
   */
  get trained(): boolean {
    return this.isTrained;
  }
}

// ============================================================================
// Optimized Product Quantization (OPQ)
// ============================================================================

/**

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Construct the ProductQuantizer with the same dimensions and numSubvectors that were used at train time (persist them with the artifact and read them back)
  2. If you intentionally changed M, re-train and re-save the codebooks
  3. Validate codebooks.length === pq.numSubvectors before calling setCodebooks, and fail with a message naming both values

Example fix

// before
const pq = new ProductQuantizer({ dimensions: 128, numSubvectors: 16 });
pq.setCodebooks(saved.codebooks); // saved with M=8 -> throws

// after
const pq = new ProductQuantizer({
  dimensions: saved.dimensions,
  numSubvectors: saved.numSubvectors,
});
pq.setCodebooks(saved.codebooks);
Defensive patterns

Strategy: validation

Validate before calling

if (codebooks.length !== pq.numSubvectors) {
  throw new Error(
    `Artifact mismatch: ${codebooks.length} codebooks for M=${pq.numSubvectors}; retrain or fix config`
  );
}
pq.setCodebooks(codebooks);

Type guard

const isCodebookArrayFor = (cbs: Codebook[], m: number): cbs is Codebook[] =>
  Array.isArray(cbs) && cbs.length === m && cbs.every(cb =>
    Array.isArray(cb.centroids) && cb.centroids.length > 0
  );

Try / catch

try {
  pq.setCodebooks(codebooks);
} catch (err) {
  if (err instanceof Error && err.message.startsWith('Expected ')) {
    throw new Error(`Stale PQ artifact (codebook count mismatch): ${err.message}`);
  }
  throw err;
}

Prevention

When it happens

Trigger: Deserializing codebooks saved from a quantizer trained with numSubvectors=8 into an instance configured with 16 (or vice versa); changing numSubvectors in options between training and loading; hand-assembling a codebook array with the wrong length.

Common situations: Tuning M for memory/speed and reusing an old artifact; loading a shared pretrained model in a service whose config drifted from the training config; forgetting to persist/re-read numSubvectors alongside the codebooks.

Related errors


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