mem0ai/mem0 · error · Error

Oracle filter operator '${operator}' does not support null

Error message

Oracle filter operator '${operator}' does not support null

What it means

Comparison operators gt, gte, lt, lte cannot compare against SQL/JSON NULL, so the adapter only permits null as the operand of eq and ne. Any other comparison operator with a null operand is rejected before SQL generation because Oracle JSON_EXISTS would not produce meaningful results.

Source

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

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

    if (operator === "in" || operator === "nin") {
      if (!Array.isArray(operand) || operand.length === 0) {
        throw new Error(
          `Oracle filter operator '${operator}' requires a non-empty array`,
        );
      }

View on GitHub (pinned to 001c235229)

Solutions

  1. Use { field: { ne: null } } for 'is not null' and { field: { eq: null } } for 'is null'.
  2. Use the field-presence form { field: '*' } to test that the key exists in the JSON payload.
  3. Strip null operands from range operators in your filter-building code before calling search().
  4. Make optional range bounds conditional: only add { field: { gte: x } } when x is not null.

Example fix

// before
filters = { score: { gt: null } }; // meaningless

// after
filters = { score: { ne: null } }; // field exists and is not null
Defensive patterns

Strategy: validation

Validate before calling

function stripNullRangeBounds(filters: any): any {
  if (Array.isArray(filters)) return filters.map(stripNullRangeBounds);
  if (!filters || typeof filters !== 'object') return filters;
  const out: Record<string, any> = {};
  for (const [k, v] of Object.entries(filters)) {
    if (v && typeof v === 'object' && !Array.isArray(v)) {
      const ops = Object.fromEntries(Object.entries(v).filter(([op, val]) => !(val === null && !['eq','ne'].includes(op))));
      if (Object.keys(ops).length) out[k] = ops;
    } else out[k] = v;
  }
  return out;
}

Try / catch

try { await memory.search('q', { filters }); } catch (e) { if (e instanceof Error && e.message.includes('does not support null')) { /* change the operator to ne/eq or remove the null bound */ } else throw e; }

Prevention

When it happens

Trigger: Filters such as { score: { gt: null } }, { updated_at: { lte: null } }, or dynamically built filters where a variable evaluated to null/undefined-coerced-to-null for a range operator.

Common situations: Optional filter parameters defaulting to null and inserted into range operators unconditionally; API code passing through client-supplied nulls; attempting an 'exists/is not null' check by comparing against null (use the '*' presence value or ne: null instead).

Related errors


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