{"record":{"id":"af3929bdbc16a844","repo":"chroma-core/chroma","slug":"message","errorCode":null,"errorMessage":"${message}","messagePattern":"\\$\\{message\\}","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"clients/new-js/packages/chromadb/src/execution/expression/rank.ts","lineNumber":19,"sourceCode":"import type { SparseVector } from \"../../api\";\nimport { deepClone, isPlainObject, IterableInput } from \"./common\";\nimport { Key } from \"./key\";\n\nexport type RankLiteral = Record<string, unknown>;\nexport type RankInput =\n  | RankExpression\n  | RankLiteral\n  | number\n  | null\n  | undefined;\n\nconst requireNumber = (value: unknown, message: string): number => {\n  if (\n    typeof value !== \"number\" ||\n    Number.isNaN(value) ||\n    !Number.isFinite(value)\n  ) {\n    throw new TypeError(message);\n  }\n  return value;\n};\n\nabstract class RankExpressionBase {\n  public abstract toJSON(): Record<string, unknown>;\n\n  public add(...others: RankInput[]): RankExpression {\n    if (others.length === 0) {\n      return this as unknown as RankExpression;\n    }\n    const expressions = [\n      this as unknown as RankExpression,\n      ...others.map((item, index) => requireRank(item, `add operand ${index}`)),\n    ];\n    return SumRankExpression.create(expressions);\n  }\n","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/clients/new-js/packages/chromadb/src/execution/expression/rank.ts#L1-L37","documentation":"This is the shared requireNumber guard in rank.ts: it throws a TypeError with a caller-supplied message whenever a value is not a number, NaN, or non-finite (Infinity/-Infinity). The concrete messages you will see are \"Val requires a numeric value\" (from Val(value)) and \"Knn default must be a number\" (from Knn({ default })). It exists because JS callers and any-typed values can bypass the TypeScript number signatures.","triggerScenarios":"Val(NaN), Val(\"1.5\"), or Val(Infinity) when building rank constants. Knn({ query, default: \"0\" }) or Knn({ default: NaN }) when supplying a default score for records missing embeddings.","commonSituations":"Rank weights parsed from config or LLM output as strings (\"1.5\") instead of numbers. Division producing Infinity (x / 0) before feeding Val(). optional-chained values that turn out to be undefined and are passed as the Knn default.","solutions":["Coerce before calling: Val(Number(weight)) with an explicit fallback for NaN","Validate finiteness at the source: if (!Number.isFinite(x)) use a default","For Knn defaults, pass a literal number (e.g. 0) or omit/null the option entirely"],"exampleFix":"// before\nconst boost = Val(cfg.weight); // cfg.weight = \"1.5\" (string) -> TypeError\n\n// after\nconst weight = Number(cfg.weight);\nconst boost = Val(Number.isFinite(weight) ? weight : 1);","handlingStrategy":"validation","validationCode":"const toFiniteNumber = (v: unknown, fallback: number): number =>\n  typeof v === \"number\" && Number.isFinite(v) ? v : fallback;\n\nconst boost = Val(toFiniteNumber(cfg.weight, 1));\nconst knn = Knn({ query, default: toFiniteNumber(cfg.defaultScore, 0) });","typeGuard":"const isFiniteNumber = (v: unknown): v is number =>\n  typeof v === \"number\" && Number.isFinite(v);","tryCatchPattern":"try {\n  const expr = Val(weight);\n} catch (e) {\n  if (e instanceof TypeError && /numeric value|must be a number/.test(e.message)) {\n    // coerce the source value (Number()) or substitute a default and rebuild\n  } else throw e;\n}","preventionTips":["Coerce config/LLM-sourced numbers with Number() and check Number.isFinite before Val()/Knn default","Watch for x / 0 producing Infinity upstream","Type rank weights as number at the config schema level"],"tags":["chroma","rank","knn","numeric"],"backgroundTag":"nan-in-numeric-input","analyzedSha":"aecdd12c8a891610db8653630b066b32ceb678b5","analyzedAt":"2026-08-16T21:53:27.228Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}