{"record":{"id":"5fa2e97fddd9a070","repo":"chroma-core/chroma","slug":"rank-input-must-be-a-rankexpression-number-or-pl","errorCode":null,"errorMessage":"Rank input must be a RankExpression, number, or plain object","messagePattern":"Rank input must be a RankExpression, number, or plain object","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"clients/new-js/packages/chromadb/src/execution/expression/rank.ts","lineNumber":118,"sourceCode":"    return MinRankExpression.create(expressions);\n  }\n}\n\nexport abstract class RankExpression extends RankExpressionBase {\n  public static from(input: RankInput): RankExpression | undefined {\n    if (input instanceof RankExpression) {\n      return input;\n    }\n    if (input === null || input === undefined) {\n      return undefined;\n    }\n    if (typeof input === \"number\") {\n      return new ValueRankExpression(input);\n    }\n    if (isPlainObject(input)) {\n      return new RawRankExpression(input);\n    }\n    throw new TypeError(\n      \"Rank input must be a RankExpression, number, or plain object\",\n    );\n  }\n}\n\nclass RawRankExpression extends RankExpression {\n  constructor(private readonly raw: RankLiteral) {\n    super();\n  }\n\n  public toJSON(): RankLiteral {\n    return deepClone(this.raw);\n  }\n}\n\nclass ValueRankExpression extends RankExpression {\n  constructor(private readonly value: number) {\n    super();","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/clients/new-js/packages/chromadb/src/execution/expression/rank.ts#L100-L136","documentation":"RankExpression.from() accepts a RankExpression instance, a number, a plain object (raw literal), or null/undefined. Anything else — notably strings (including numeric strings like \"5\"), arrays, and non-plain class instances — raises this TypeError. Because requireRank() in rank.ts routes operands of add/subtract/multiply/divide/max/min through this same function, arithmetic on rank expressions fails identically.","triggerScenarios":"score.add(\"weight\") or rankExpr.multiply([1, 2]); Rrf({ ranks: [\"bm25\"] }). Passing a JSON string that was never parsed, or a Map/typed instance instead of a plain object.","commonSituations":"Mixing string weights from config or LLM output into rank arithmetic instead of numbers or Val(...). Forgetting JSON.parse on serialized rank expressions. Assuming numeric strings coerce (they do not — typeof \"5\" is \"string\").","solutions":["Use numbers or Val() for constants: score.multiply(0.5) or score.multiply(Val(weight))","Parse serialized expressions before passing: RankExpression.from(JSON.parse(raw))","Convert numeric strings upstream: Number(weight) at the config boundary"],"exampleFix":"// before\nconst combined = knn.multiply(cfg.weight); // cfg.weight = \"0.5\" string -> TypeError\n\n// after\nconst weight = Number(cfg.weight);\nconst combined = knn.multiply(Number.isFinite(weight) ? weight : 1);","handlingStrategy":"type-guard","validationCode":"const toRankOperand = (v: unknown): number | RankExpression => {\n  if (typeof v === \"string\") {\n    const n = Number(v);\n    if (Number.isFinite(n)) return n;\n  }\n  if (typeof v === \"number\" || v instanceof RankExpression || (typeof v === \"object\" && v !== null)) {\n    return v as number | RankExpression;\n  }\n  throw new Error(\"Rank operands must be numbers, rank expressions, or plain objects\");\n};\nconst combined = knn.multiply(toRankOperand(cfg.weight));","typeGuard":"function isRankInput(v: unknown): v is number | RankExpression | Record<string, unknown> {\n  return (\n    typeof v === \"number\" ||\n    v instanceof RankExpression ||\n    (typeof v === \"object\" && v !== null && !Array.isArray(v) && v.constructor === Object)\n  );\n}","tryCatchPattern":"try {\n  const expr = Rrf({ ranks: [knn, bm25, cfg.extra] });\n} catch (e) {\n  if (e instanceof TypeError && /Rank input|must be a rank expression/.test(e.message)) {\n    // drop or coerce the offending operand (Number(\"0.5\")) and rebuild\n  } else throw e;\n}","preventionTips":["Never pass strings into rank arithmetic — numeric strings are rejected, unlike JS coercion elsewhere","Parse serialized rank expressions with JSON.parse first","Keep rank weights typed as number from config ingestion onward"],"tags":["chroma","rank","expression","typeerror"],"backgroundTag":"wrong-argument-type","analyzedSha":"aecdd12c8a891610db8653630b066b32ceb678b5","analyzedAt":"2026-08-16T21:53:27.228Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}