{"record":{"id":"1e0dda365296036c","repo":"mem0ai/mem0","slug":"oracle-filter-operator-operator-requires-a-sc","errorCode":null,"errorMessage":"Oracle filter operator '${operator}' requires a scalar value","messagePattern":"Oracle filter operator '(.+?)' requires a scalar value","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"mem0-ts/src/oss/src/vector_stores/oracledb.ts","lineNumber":168,"sourceCode":"  }\n\n  const unsupported = operators\n    .map(([op]) => op)\n    .filter((op) => !FIELD_OPERATORS.has(op));\n  if (unsupported.length > 0) {\n    throw new Error(\n      `Unsupported Oracle filter operator(s) for field '${metadataKey}': ${unsupported.sort().join(\", \")}`,\n    );\n  }\n\n  const predicates: string[] = [];\n  const passings: string[] = [];\n  const additionalClauses: string[] = [];\n\n  for (const [operator, operand] of operators) {\n    if (operator in COMPARISON_OPERATORS) {\n      if (!isScalar(operand)) {\n        throw new Error(\n          `Oracle filter operator '${operator}' requires a scalar value`,\n        );\n      }\n      if (operand === null) {\n        if (operator !== \"eq\" && operator !== \"ne\") {\n          throw new Error(\n            `Oracle filter operator '${operator}' does not support null`,\n          );\n        }\n        predicates.push(`@ ${COMPARISON_OPERATORS[operator]} null`);\n        continue;\n      }\n      const [variable, passing] = bindFilterValue(operand, binds);\n      predicates.push(`@ ${COMPARISON_OPERATORS[operator]} ${variable}`);\n      passings.push(passing);\n      continue;\n    }\n","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/mem0ai/mem0/blob/001c235229be8795e3834520467bd0d661ed8f34/mem0-ts/src/oss/src/vector_stores/oracledb.ts#L150-L186","documentation":"Thrown when a comparison operator (eq, ne, gt, gte, lt, lte) receives a non-scalar operand. isScalar() only accepts null, string, number, and boolean; objects and arrays fail the check because Oracle JSON_EXISTS comparison predicates bind a single scalar bind variable per comparison.","triggerScenarios":"Passing filters like { score: { gt: { value: 5 } } } (object operand), { tags: { eq: ['a','b'] } } (array operand — use 'in' instead), or { ts: { gte: new Date(...) } } (Date is typeof 'object', hence non-scalar).","commonSituations":"Accidentally wrapping a value in an extra object; passing arrays to eq/ne where in/nin was intended; passing Date objects instead of ISO strings or epoch numbers; passing nested filter objects as the operand of a comparison operator.","solutions":["Use a plain scalar: { score: { gt: 5 } } instead of { score: { gt: { value: 5 } } }.","For array membership use 'in'/'nin': { tags: { in: ['a','b'] } } instead of eq with an array.","Serialize Dates explicitly: { created_at: { gte: '2026-01-01T00:00:00Z' } } or use an epoch number.","Unwrap accidental double nesting produced by generic filter-builder code."],"exampleFix":"// before\nfilters = { created_at: { gte: new Date('2026-01-01') } };\n\n// after\nfilters = { created_at: { gte: '2026-01-01T00:00:00.000Z' } };","handlingStrategy":"type-guard","validationCode":"function assertScalarOperands(filters: any): void {\n  if (!filters || typeof filters !== 'object') return;\n  for (const [key, value] of Object.entries(filters)) {\n    if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\n      for (const [op, operand] of Object.entries(value)) {\n        if (['eq','ne','gt','gte','lt','lte'].includes(op) && (typeof operand === 'object' || Array.isArray(operand))) {\n          throw new TypeError(`Filter '${key}.${op}' must be scalar, got ${JSON.stringify(operand)}`);\n        }\n      }\n    }\n  }\n}","typeGuard":"const isScalar = (v: unknown): v is string | number | boolean | null =>\n  v === null || ['string', 'number', 'boolean'].includes(typeof v);","tryCatchPattern":"try { await memory.search('q', { filters }); } catch (e) { if (e instanceof Error && e.message.includes('requires a scalar value')) { /* find the object/array operand and replace with a primitive or in-list */ } else throw e; }","preventionTips":["Serialize Date operands to ISO strings at the API boundary.","Use in/nin instead of eq with arrays.","Never wrap operands in { value: x } style objects."],"tags":["oracle","filters","validation","scalar","typescript"],"backgroundTag":null,"analyzedSha":"001c235229be8795e3834520467bd0d661ed8f34","analyzedAt":"2026-08-15T01:55:42.685Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}