mem0ai/mem0 · error · Error

Oracle filter operator '${operator}' requires scalar values

Error message

Oracle filter operator '${operator}' requires scalar values

What it means

Each element of an in/nin array is bound as an individual scalar bind variable in the JSON_EXISTS PASSING clause. Nested objects, arrays, or other non-scalar elements cannot be bound, so any non-scalar item is rejected.

Source

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

      }
      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`,
        );
      }

      const variables: string[] = [];
      const listPassings: string[] = [];
      for (const item of operand) {
        if (!isScalar(item)) {
          throw new Error(
            `Oracle filter operator '${operator}' requires scalar values`,
          );
        }
        if (item === null) {
          variables.push("null");
          continue;
        }
        const [variable, passing] = bindFilterValue(item, binds);
        variables.push(variable);
        listPassings.push(passing);
      }

      const membership = jsonExists(
        path,
        `@ in (${variables.join(", ")})`,
        listPassings,
      );
      additionalClauses.push(

View on GitHub (pinned to 001c235229)

Solutions

  1. Map the list to primitives before filtering: ids.map(u => u.id).
  2. Flatten nested arrays or use OR-groups of contains filters for nested matching.
  3. Filter out non-scalar entries: list.filter(v => v === null || ['string','number','boolean'].includes(typeof v)).
  4. Validate list shape in one place (a shared filter sanitizer) before calling search().

Example fix

// before
filters = { user_id: { in: users } }; // array of objects

// after
filters = { user_id: { in: users.map((u) => u.id) } };
Defensive patterns

Strategy: validation

Validate before calling

const isScalar = (v: unknown) => v === null || ['string','number','boolean'].includes(typeof v);
function assertScalarList(field: string, op: string, list: unknown[]): void {
  const bad = list.filter((v) => !isScalar(v));
  if (bad.length) throw new TypeError(`${field}.${op} contains non-scalar items: ${JSON.stringify(bad[0])}`);
}

Type guard

const isScalarList = (v: unknown): v is (string | number | boolean | null)[] =>
  Array.isArray(v) && v.every((x) => x === null || ['string','number','boolean'].includes(typeof x));

Try / catch

try { await memory.search('q', { filters }); } catch (e) { if (e instanceof Error && e.message.includes('requires scalar values')) { /* map list items to primitives (e.g. x.id) and retry */ } else throw e; }

Prevention

When it happens

Trigger: { items: { in: [['a','b'], 'c'] } } (nested array), { refs: { in: [{ id: 1 }, { id: 2 }] } } (objects), or a list produced by map() that accidentally returns objects instead of primitive field values.

Common situations: Forgetting to extract a field: users.map(u => u) instead of users.map(u => u.id); JSON-parsed payloads containing mixed shapes; mixing null (allowed) with objects (not allowed) in one list.

Related errors


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