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
- Construct the ProductQuantizer with the same dimensions and numSubvectors that were used at train time (persist them with the artifact and read them back)
- If you intentionally changed M, re-train and re-save the codebooks
- 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
- Persist dimensions and numSubvectors inside the artifact and construct the quantizer from them on load
- Bump an artifact version field whenever training config changes and refuse to load older versions
- Never hardcode numSubvectors at the load site
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
- Cannot calibrate with empty samples
- Expected ${this.dimensions}x${this.dimensions} matrix
- Original and reconstructed arrays must have same length
- localCompute: no adapter for graphId=${input.graphId}
- Invalid completion type
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/0136094fa26ae81d.
Report an issue: GitHub.