mem0ai/mem0 · error · Error

Oracle filter operator '${operator}' requires a scalar value

Error message

Oracle filter operator '${operator}' requires a scalar value

What it means

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.

Source

Thrown at mem0-ts/src/oss/src/vector_stores/oracledb.ts:168

  }

  const unsupported = operators
    .map(([op]) => op)
    .filter((op) => !FIELD_OPERATORS.has(op));
  if (unsupported.length > 0) {
    throw new Error(
      `Unsupported Oracle filter operator(s) for field '${metadataKey}': ${unsupported.sort().join(", ")}`,
    );
  }

  const predicates: string[] = [];
  const passings: string[] = [];
  const additionalClauses: string[] = [];

  for (const [operator, operand] of operators) {
    if (operator in COMPARISON_OPERATORS) {
      if (!isScalar(operand)) {
        throw new Error(
          `Oracle filter operator '${operator}' requires a scalar value`,
        );
      }
      if (operand === null) {
        if (operator !== "eq" && operator !== "ne") {
          throw new Error(
            `Oracle filter operator '${operator}' does not support null`,
          );
        }
        predicates.push(`@ ${COMPARISON_OPERATORS[operator]} null`);
        continue;
      }
      const [variable, passing] = bindFilterValue(operand, binds);
      predicates.push(`@ ${COMPARISON_OPERATORS[operator]} ${variable}`);
      passings.push(passing);
      continue;
    }

View on GitHub (pinned to 001c235229)

Solutions

  1. Use a plain scalar: { score: { gt: 5 } } instead of { score: { gt: { value: 5 } } }.
  2. For array membership use 'in'/'nin': { tags: { in: ['a','b'] } } instead of eq with an array.
  3. Serialize Dates explicitly: { created_at: { gte: '2026-01-01T00:00:00Z' } } or use an epoch number.
  4. Unwrap accidental double nesting produced by generic filter-builder code.

Example fix

// before
filters = { created_at: { gte: new Date('2026-01-01') } };

// after
filters = { created_at: { gte: '2026-01-01T00:00:00.000Z' } };
Defensive patterns

Strategy: type-guard

Validate before calling

function assertScalarOperands(filters: any): void {
  if (!filters || typeof filters !== 'object') return;
  for (const [key, value] of Object.entries(filters)) {
    if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
      for (const [op, operand] of Object.entries(value)) {
        if (['eq','ne','gt','gte','lt','lte'].includes(op) && (typeof operand === 'object' || Array.isArray(operand))) {
          throw new TypeError(`Filter '${key}.${op}' must be scalar, got ${JSON.stringify(operand)}`);
        }
      }
    }
  }
}

Type guard

const isScalar = (v: unknown): v is string | number | boolean | null =>
  v === null || ['string', 'number', 'boolean'].includes(typeof v);

Try / catch

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; }

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of mem0ai/mem0@001c235229 (2026-08-15). Data as JSON: /api/errors/1e0dda365296036c. Report an issue: GitHub.