chroma-core/chroma · error · TypeError
Rrf k must be a positive integer
Error message
Rrf k must be a positive integer
What it means
Thrown by the Rrf (reciprocal rank fusion) factory in the Chroma JS client (rank.ts:462) when its `k` smoothing constant — which defaults to 60 — is not an integer greater than zero. k is used as rank.add(k) in the fusion formula 1/(rank+k), so 0 or fractional values are rejected at expression-build time, client-side, before any request. Note k is validated before `ranks`, so a bad k masks an empty-ranks problem.
Source
Thrown at clients/new-js/packages/chromadb/src/execution/expression/rank.ts:462
export const Knn = (options: KnnOptions): RankExpression =>
new KnnRankExpression(normalizeKnnOptions(options));
export interface RrfOptions {
ranks: RankInput[];
k?: number;
weights?: number[];
normalize?: boolean;
}
export const Rrf = ({
ranks,
k = 60,
weights,
normalize = false,
}: RrfOptions): RankExpression => {
if (!Number.isInteger(k) || k <= 0) {
throw new TypeError("Rrf k must be a positive integer");
}
if (!Array.isArray(ranks) || ranks.length === 0) {
throw new TypeError("Rrf requires at least one rank expression");
}
const expressions = ranks.map((rank, index) =>
requireRank(rank, `ranks[${index}]`),
);
let weightValues = weights
? weights.slice()
: new Array(expressions.length).fill(1);
if (weightValues.length !== expressions.length) {
throw new Error("Number of weights must match number of ranks");
}
if (weightValues.some((value) => typeof value !== "number" || value < 0)) {
throw new TypeError("Weights must be non-negative numbers");
}View on GitHub (pinned to aecdd12c8a)
Solutions
- Use an integer k >= 1, or omit k to keep the default of 60
- If k comes from config, convert and validate: Number.isInteger(k) && k > 0, otherwise fall back to 60
- Fix the upstream formula so it yields an integer (Math.round/Math.trunc)
Example fix
// before
const fused = Rrf({ ranks, k: Number(cfg.rrfK) }); // NaN or 0.5 throws
// after
const rawK = Number(cfg.rrfK);
const fused = Rrf({ ranks, k: Number.isInteger(rawK) && rawK > 0 ? rawK : undefined }); Defensive patterns
Strategy: validation
Validate before calling
const safeK = (v: unknown): number | undefined =>
typeof v === 'number' && Number.isInteger(v) && v > 0 ? v : undefined;
const fused = Rrf({ ranks, k: safeK(cfg.rrfK) }); // undefined -> default 60 Type guard
const isPositiveInteger = (v: unknown): v is number => typeof v === 'number' && Number.isInteger(v) && v > 0;
Try / catch
try {
const fused = Rrf({ ranks, k });
} catch (e) {
if (e instanceof TypeError && e.message.includes('Rrf k')) {
return Rrf({ ranks }); // default k=60
}
throw e;
} Prevention
- Convert config values: string '60' fails Number.isInteger
- Round computed constants: Math.max(1, Math.round(k))
- Remember k is validated before ranks — a bad k hides an empty-ranks problem
When it happens
Trigger: Calling Rrf({ ranks, k: 0 }), k: -1, k: 0.5, or k: NaN. Typical sources: k read from config/env without parsing (string '60' is not a number and fails Number.isInteger), or k computed as a float (e.g. ranks.length / 2 with an odd count).
Common situations: Tuning RRF smoothing from external config where the value arrives as a string; formulas that produce fractional constants; copying literature values like k=1.2 (fractional) which this client rejects; setting k=0 intending 'no smoothing', which would cause division by rank 0.
Related errors
- Knn limit must be a positive integer
- Knn key must be a string or Key instance
- ${context} must be a rank expression
- Rrf requires at least one rank expression
- Number of weights must match number of ranks
AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16).
Data as JSON: /api/errors/78a964b71910826d.
Report an issue: GitHub.