mem0ai/mem0 · error · Error

Logical filter operator '${key}' requires a non-empty array

Error message

Logical filter operator '${key}' requires a non-empty array

What it means

Logical operators ($and/$or/$not or AND/OR/NOT) must map to a non-empty array of sub-conditions because the adapter joins the nested clauses with AND/OR inside parentheses; an empty or non-array value yields invalid SQL. The check runs before recursing into buildFilterGroup for each sub-condition.

Source

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

  return clauses.length === 1 ? clauses[0] : `(${clauses.join(" AND ")})`;
}

export function buildFilterGroup(
  filters: Record<string, any>,
  binds: Record<string, any>,
): string {
  const entries = Object.entries(filters ?? {});
  if (entries.length === 0) {
    throw new Error("Oracle filter groups must be non-empty objects");
  }

  const clauses: string[] = [];
  for (const [key, value] of entries) {
    const logicalOperator = LOGICAL_OPERATORS[key];
    if (logicalOperator) {
      if (!Array.isArray(value) || value.length === 0) {
        throw new Error(
          `Logical filter operator '${key}' requires a non-empty array`,
        );
      }
      const nested = value.map((condition) =>
        buildFilterGroup(condition, binds),
      );
      if (logicalOperator === "not") {
        clauses.push(`NOT (${nested.join(" OR ")})`);
      } else {
        clauses.push(
          `(${nested.join(logicalOperator === "and" ? " AND " : " OR ")})`,
        );
      }
      continue;
    }

    if (key.startsWith("$")) {
      throw new Error(`Unsupported Oracle logical filter operator: ${key}`);

View on GitHub (pinned to 001c235229)

Solutions

  1. Use at least one sub-condition: { $and: [{ a: 1 }] }, or omit the logical wrapper entirely for a single condition ({ a: 1 }).
  2. In builder code, only wrap in $and/$or when conditions.length > 1.
  3. Wrap single objects into arrays: { $or: [cond] } not { $or: cond }.
  4. Remember $not takes an array of conditions and negates their OR-join; field-level negation uses the ne operator.

Example fix

// before
const filters = { $and: conditions }; // conditions may be []

// after
const filters = conditions.length > 1 ? { $and: conditions } : conditions[0];
Defensive patterns

Strategy: validation

Validate before calling

function buildAnd(conditions: Record<string, any>[]): Record<string, any> | undefined {
  const valid = conditions.filter((c) => c && Object.keys(c).length > 0);
  if (valid.length === 0) return undefined;
  if (valid.length === 1) return valid[0];
  return { $and: valid };
}

Type guard

const isNonEmptyConditionArray = (v: unknown): v is Record<string, unknown>[] =>
  Array.isArray(v) && v.length > 0 && v.every((c) => !!c && typeof c === 'object' && !Array.isArray(c) && Object.keys(c).length > 0);

Prevention

When it happens

Trigger: { $and: [] }, { $or: 'x' }, { $not: {} } (object instead of array), or { AND: [{}] } where the inner condition object is empty — the empty inner object then fails error 266's check inside the recursion.

Common situations: Programmatic filter builders that always emit a top-level $and even when no conditions were collected; a client serializing a single condition as an object instead of a one-element array; copying Mongo syntax where some drivers accept $not on a field.

Related errors


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