{"record":{"id":"337b1990a7b135ff","repo":"chroma-core/chroma","slug":"knn-limit-must-be-a-positive-integer","errorCode":null,"errorMessage":"Knn limit must be a positive integer","messagePattern":"Knn limit must be a positive integer","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"clients/new-js/packages/chromadb/src/execution/expression/rank.ts","lineNumber":385,"sourceCode":"  if (Array.isArray(vector)) {\n    return vector.slice();\n  }\n  return Array.from(vector as Iterable<number>, (value) => {\n    if (\n      typeof value !== \"number\" ||\n      Number.isNaN(value) ||\n      !Number.isFinite(value)\n    ) {\n      throw new TypeError(\"Dense query vector values must be finite numbers\");\n    }\n    return value;\n  });\n};\n\nconst normalizeKnnOptions = (options: KnnOptions): KnnOptionsNormalized => {\n  const limit = options.limit ?? 128;\n  if (!Number.isInteger(limit) || limit <= 0) {\n    throw new TypeError(\"Knn limit must be a positive integer\");\n  }\n\n  const queryInput = options.query;\n\n  let query: number[] | SparseVector | string;\n  if (typeof queryInput === \"string\") {\n    query = queryInput;\n  } else if (\n    isPlainObject(queryInput) &&\n    Array.isArray((queryInput as SparseVector).indices) &&\n    Array.isArray((queryInput as SparseVector).values)\n  ) {\n    const sparse = queryInput as SparseVector;\n    query = {\n      indices: sparse.indices.slice(),\n      values: sparse.values.slice(),\n    };\n  } else {","sourceCodeStart":367,"sourceCodeEnd":403,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/clients/new-js/packages/chromadb/src/execution/expression/rank.ts#L367-L403","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Set limit to a positive integer (>= 1) or omit it entirely to use the default of 128","If limit is dynamic, coerce and clamp before calling: limit = Math.max(1, Math.trunc(limit))","Validate external config before use: reject unless typeof x === 'number' && Number.isInteger(x) && x > 0"],"exampleFix":"// before\nconst rank = Knn({ query: embedding, limit: Number(input.limit) }); // 0 or NaN throws\n\n// after\nconst raw = Number(input.limit);\nconst limit = Number.isInteger(raw) && raw > 0 ? raw : undefined; // undefined -> default 128\nconst rank = Knn({ query: embedding, limit });","handlingStrategy":"validation","validationCode":"const safeLimit = (v: unknown): number | undefined =>\n  typeof v === 'number' && Number.isInteger(v) && v > 0 ? v : undefined;\nconst rank = Knn({ query: vec, limit: safeLimit(userLimit) }); // undefined -> default 128","typeGuard":"const isPositiveInteger = (v: unknown): v is number =>\n  typeof v === 'number' && Number.isInteger(v) && v > 0;","tryCatchPattern":"try {\n  const rank = Knn({ query: vec, limit });\n} catch (e) {\n  if (e instanceof TypeError && e.message.includes('Knn limit')) {\n    return Knn({ query: vec }); // retry with default limit\n  }\n  throw e;\n}","preventionTips":["Validate limits from env/query strings: Number('') === 0 and Number('abc') === NaN both throw inside Knn","Omit limit to accept the default of 128","Clamp dynamic values: Math.max(1, Math.trunc(limit))"],"tags":["knn","limit","input-validation","rank-expression","client-side"],"backgroundTag":"invalid-argument-value","analyzedSha":"aecdd12c8a891610db8653630b066b32ceb678b5","analyzedAt":"2026-08-16T21:53:27.228Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}