ruvnet/ruflo · error
Need at least ${this.numCentroids} training vectors, got ${v
Error message
Need at least ${this.numCentroids} training vectors, got ${vectors.length} What it means
ProductQuantizer.train() (quantization.ts:712) runs k-means per subvector with numCentroids clusters (typically 256 so each code fits one byte). k-means cannot produce K distinct centroids from fewer than K training vectors, so the method throws when vectors.length < numCentroids, reporting both numbers.
Source
Thrown at v3/@claude-flow/plugins/src/integrations/ruvector/quantization.ts:712
throw new Error(
`Dimensions (${options.dimensions}) must be divisible by numSubvectors (${options.numSubvectors})`
);
}
this.subvectorDim = options.dimensions / options.numSubvectors;
this.maxIterations = options.maxIterations ?? 100;
this.tolerance = options.tolerance ?? 1e-6;
this.rng = createRng(options.seed ?? 42);
}
/**
* Trains codebooks from training data using k-means clustering.
*
* @param vectors - Training vectors
*/
async train(vectors: number[][]): Promise<void> {
if (vectors.length < this.numCentroids) {
throw new Error(
`Need at least ${this.numCentroids} training vectors, got ${vectors.length}`
);
}
this.codebooks = [];
// Train a codebook for each subvector
for (let m = 0; m < this.numSubvectors; m++) {
// Extract subvectors
const subvectors = this.extractSubvectors(vectors, m);
// Train codebook using k-means
const codebook = await this.trainCodebook(subvectors);
this.codebooks.push(codebook);
}
this.isTrained = true;
}View on GitHub (pinned to fa13ee4ad6)
Solutions
- Collect at least numCentroids training vectors (256 for byte-sized codes) before calling train()
- Lower numCentroids to fit small datasets (e.g. 16 or 32) — compression and recall adjust accordingly
- Sample vectors from the real corpus rather than a fixed fixture in tests, or generate >= K synthetic vectors for smoke tests
Example fix
// before
const pq = new ProductQuantizer({ dimensions: 128, numSubvectors: 8, numCentroids: 256 });
await pq.train(sample.slice(0, 50)); // 50 < 256 -> throws
// after
await pq.train(sample); // ensure sample.length >= 256
// or for small datasets:
const pq = new ProductQuantizer({ dimensions: 128, numSubvectors: 8, numCentroids: 16 }); Defensive patterns
Strategy: validation
Validate before calling
if (vectors.length < pqNumCentroids) {
throw new Error(`PQ training needs >= ${pqNumCentroids} vectors, dataset has ${vectors.length}`);
}
await pq.train(vectors); Type guard
function hasEnoughTrainingData(vectors: number[][], numCentroids: number): boolean {
return vectors.length >= numCentroids;
} Try / catch
try {
await pq.train(vectors);
} catch (err) {
if (err instanceof Error && err.message.includes('training vectors')) {
const small = new ProductQuantizer({ ...opts, numCentroids: 16 });
await small.train(vectors);
} else throw err;
} Prevention
- Check dataset size against numCentroids (256 for byte codes) before training
- Lower numCentroids for small corpora instead of forcing K=256
- Guard smoke tests to either generate >= K vectors or use a small K
When it happens
Trigger: Training with K=256 on a dataset of 100 vectors; smoke tests using a handful of fixtures; production corpora smaller than the advertised codebook size.
Common situations: See trigger scenarios.
Related errors
- Cannot learn thresholds from empty samples
- Dimensions (${options.dimensions}) must be divisible by numS
- ProductQuantizer must be trained before encoding
- Cannot calibrate with empty samples
- ProductQuantizer must be trained before decoding
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/2be2f5f5e0a5ca3d.
Report an issue: GitHub.