mem0ai/mem0 · error · Error

Oracle filter groups must be non-empty objects

Error message

Oracle filter groups must be non-empty objects

What it means

buildFilterGroup requires a non-empty filter object so it can emit at least one SQL clause; Object.entries(filters ?? {}) returning zero entries means there is nothing to translate. Note that undefined/null filters never reach here (buildWhereClause short-circuits them) — only an explicitly empty object {} or an empty nested group triggers it.

Source

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

      passings.push(passing);
    }
  }

  const clauses = [...additionalClauses];
  if (predicates.length > 0) {
    clauses.unshift(jsonExists(path, predicates.join(" && "), passings));
  }

  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(

View on GitHub (pinned to 001c235229)

Solutions

  1. Pass undefined (or omit the filters key) instead of an empty object when no filtering is needed.
  2. In filter-composition helpers, return undefined when the resulting object has no keys.
  3. Validate and drop empty nested groups: { $and: parts.filter(p => Object.keys(p).length > 0) }.
  4. Add an application-level check before search(): if (!Object.keys(filters).length) filters = undefined.

Example fix

// before
await memory.search('q', { filters: {} });

// after
const filters = Object.keys(built).length ? built : undefined;
await memory.search('q', { filters });
Defensive patterns

Strategy: validation

Validate before calling

function dropEmptyGroups(filters: any): any {
  if (Array.isArray(filters)) {
    const nested = filters.map(dropEmptyGroups).filter((f) => f !== undefined);
    return nested; // caller decides whether the array is still non-empty
  }
  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) && Object.keys(v).length === 0) continue;
    out[k] = dropEmptyGroups(v);
  }
  return Object.keys(out).length ? out : undefined;
}

Type guard

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

Prevention

When it happens

Trigger: search('q', { filters: {} }); or a nested group like { $and: [{}] } where an inner condition object is empty; also { $or: [] } style inputs filtered down to an empty object by upstream code.

Common situations: Dynamically composing filters where every optional key was omitted, leaving {}; spreading optional params into a base object that stays empty; forwarding a client's {} query parameter verbatim.

Related errors


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