chroma-core/chroma · error · TypeError

Knn limit must be a positive integer

Error message

Knn limit must be a positive integer

What it means

Thrown client-side by the Chroma JS client when building a KNN rank expression: normalizeKnnOptions (rank.ts:384) validates that Knn()'s `limit` option, which defaults to 128, is an integer greater than zero. The limit becomes the `limit` field of the {$knn: ...} JSON sent to the server, so zero, negative, fractional, NaN, or Infinity values are rejected before any network call is made. It is a TypeError, not a server response.

Source

Thrown at clients/new-js/packages/chromadb/src/execution/expression/rank.ts:385

  if (Array.isArray(vector)) {
    return vector.slice();
  }
  return Array.from(vector as Iterable<number>, (value) => {
    if (
      typeof value !== "number" ||
      Number.isNaN(value) ||
      !Number.isFinite(value)
    ) {
      throw new TypeError("Dense query vector values must be finite numbers");
    }
    return value;
  });
};

const normalizeKnnOptions = (options: KnnOptions): KnnOptionsNormalized => {
  const limit = options.limit ?? 128;
  if (!Number.isInteger(limit) || limit <= 0) {
    throw new TypeError("Knn limit must be a positive integer");
  }

  const queryInput = options.query;

  let query: number[] | SparseVector | string;
  if (typeof queryInput === "string") {
    query = queryInput;
  } else if (
    isPlainObject(queryInput) &&
    Array.isArray((queryInput as SparseVector).indices) &&
    Array.isArray((queryInput as SparseVector).values)
  ) {
    const sparse = queryInput as SparseVector;
    query = {
      indices: sparse.indices.slice(),
      values: sparse.values.slice(),
    };
  } else {

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Set limit to a positive integer (>= 1) or omit it entirely to use the default of 128
  2. If limit is dynamic, coerce and clamp before calling: limit = Math.max(1, Math.trunc(limit))
  3. Validate external config before use: reject unless typeof x === 'number' && Number.isInteger(x) && x > 0

Example fix

// before
const rank = Knn({ query: embedding, limit: Number(input.limit) }); // 0 or NaN throws

// after
const raw = Number(input.limit);
const limit = Number.isInteger(raw) && raw > 0 ? raw : undefined; // undefined -> default 128
const rank = Knn({ query: embedding, limit });
Defensive patterns

Strategy: validation

Validate before calling

const safeLimit = (v: unknown): number | undefined =>
  typeof v === 'number' && Number.isInteger(v) && v > 0 ? v : undefined;
const rank = Knn({ query: vec, limit: safeLimit(userLimit) }); // undefined -> default 128

Type guard

const isPositiveInteger = (v: unknown): v is number =>
  typeof v === 'number' && Number.isInteger(v) && v > 0;

Try / catch

try {
  const rank = Knn({ query: vec, limit });
} catch (e) {
  if (e instanceof TypeError && e.message.includes('Knn limit')) {
    return Knn({ query: vec }); // retry with default limit
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling Knn({ query: vector, limit: 0 }), limit: -5, limit: 10.5, limit: NaN, or limit: Infinity. Typical real trigger: limit derived from unvalidated input, e.g. Number(process.env.KNN_LIMIT) when the var is empty (Number('') === 0) or non-numeric (NaN), or a limit computed as a float like n / 2 with odd n.

Common situations: Pagination limits read from env vars or query strings without validation; spreading user-supplied options objects into Knn(); porting code from an API where limit 0 meant 'use default'; limits computed dynamically (division, averaging) that yield non-integers.

Related errors


AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16). Data as JSON: /api/errors/337b1990a7b135ff. Report an issue: GitHub.