mem0ai/mem0 · error · Error

Unsupported Oracle filter operator(s) for field '${metadataK

Error message

Unsupported Oracle filter operator(s) for field '${metadataKey}': ${unsupported.sort().join(", ")}

What it means

Thrown while translating a MongoDB-style field filter into an Oracle JSON_EXISTS predicate. buildFieldCondition inspects the operator object for a field and rejects any operator key not in FIELD_OPERATORS (eq, ne, gt, gte, lt, lte, in, nin, contains, icontains). This guard exists because the Oracle JSON path language only supports a fixed comparison subset, so unknown operators cannot be mapped to SQL.

Source

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

  if (Array.isArray(value)) {
    throw new Error(
      `Oracle filter for field '${metadataKey}' must be a scalar or an operator object`,
    );
  }

  const operators = Object.entries(value);
  if (operators.length === 0) {
    throw new Error(
      `Operator filter for field '${metadataKey}' must not be empty`,
    );
  }

  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(

View on GitHub (pinned to 001c235229)

Solutions

  1. Rewrite the filter using only supported operators: eq, ne, gt, gte, lt, lte, in, nin, contains, icontains — without the '$' prefix.
  2. Replace '$in' with 'in' and '$nin' with 'nin'; the Oracle adapter uses unprefixed operator names.
  3. Replace unsupported operators with supported equivalents: $regex → contains/icontains on strings, $exists → the '*' value (field presence check), $gt/$gte/$lt/$lte → gt/gte/lt/lte.
  4. Run search() without filters and post-filter in application code if the predicate cannot be expressed with the supported set.

Example fix

// before
await memory.search('query', { filters: { user_id: { $in: ['u1','u2'] } } });

// after
await memory.search('query', { filters: { user_id: { in: ['u1', 'u2'] } } });
Defensive patterns

Strategy: validation

Validate before calling

const FIELD_OPERATORS = new Set(['eq','ne','gt','gte','lt','lte','in','nin','contains','icontains']);
function validateFieldFilters(filters: any, path = 'filters'): void {
  if (!filters || typeof filters !== 'object') return;
  for (const [key, value] of Object.entries(filters)) {
    if (key.startsWith('$') || key === 'AND' || key === 'OR' || key === 'NOT') {
      if (Array.isArray(value)) value.forEach((c, i) => validateFieldFilters(c, `${path}.${key}[${i}]`));
      continue;
    }
    if (value && typeof value === 'object' && !Array.isArray(value)) {
      const bad = Object.keys(value).filter((op) => !FIELD_OPERATORS.has(op));
      if (bad.length) throw new RangeError(`${path}: unsupported operators ${bad.join(', ')} on field '${key}'`);
    }
  }
}

Type guard

function isSupportedFieldFilter(v: any): boolean {
  return v !== null && typeof v === 'object' && !Array.isArray(v) &&
    Object.keys(v).every((op) => ['eq','ne','gt','gte','lt','lte','in','nin','contains','icontains'].includes(op));
}

Try / catch

try { await memory.search('q', { filters }); } catch (e) { if (e instanceof Error && e.message.includes('Unsupported Oracle filter operator')) { /* rewrite or drop the offending operators, retry without them */ } else throw e; }

Prevention

When it happens

Trigger: Calling search()/getAll() with filters like { user_id: { $eq: 'u1', $regex: '.*' } } — '$regex' is not in FIELD_OPERATORS and triggers the error listing '$regex'. Any filter object under a field key containing operators such as $exists, $size, $all, $elemMatch, $between, or $not (field-level) will be rejected.

Common situations: Copying filter syntax from the MongoDB docs or from another mem0 vector store backend (e.g. Qdrant/pgvector) that supports a wider operator set; using '$in' instead of the required 'in' (no dollar prefix); writing nested operator objects where a plain value was expected.

Related errors


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