mem0ai/mem0 · error · Error

$not filter requires a non-empty list

Error message

$not filter requires a non-empty list

What it means

$not in S3 Vectors filters must be a non-empty array of sub-filter objects. An empty or non-array value throws before translation, since negating nothing has no defined behavior in the store's filter model.

Source

Thrown at mem0-ts/src/oss/src/vector_stores/s3_vectors.ts:536

            (entry) => !this.isAlwaysFalseFilter(entry),
          );
          if (viableEntries.length === 0) {
            return { [ALWAYS_FALSE_FILTER_KEY]: true };
          }
          clauses.push(
            viableEntries.length === 1
              ? viableEntries[0]
              : { [key]: viableEntries },
          );
          continue;
        }
        clauses.push(entries.length === 1 ? entries[0] : { [key]: entries });
        continue;
      }

      if (key === "$not") {
        if (!Array.isArray(value) || value.length === 0) {
          throw new Error("$not filter requires a non-empty list");
        }

        const normalizedEntries = value.map((entry) =>
          this.convertFilterNode(entry),
        );
        if (normalizedEntries.some((entry) => this.isNoOpFilter(entry))) {
          return { [ALWAYS_FALSE_FILTER_KEY]: true };
        }
        const negated = normalizedEntries.filter(
          (entry) => !this.isAlwaysFalseFilter(entry),
        );
        if (negated.length === 0) {
          continue;
        }
        const negatedFilters = negated.map((entry) => this.negateFilter(entry));
        clauses.push(
          negatedFilters.length === 1
            ? negatedFilters[0]

View on GitHub (pinned to 001c235229)

Solutions

  1. Drop the $not key when the exclusion list is empty
  2. Build conditionally: const filters = exclusions.length ? { $not: exclusions } : {}
  3. Reject empty $not arrays when validating external filter payloads

Example fix

// before
const filters = { $not: excludeTags.map(t => ({ tag: { eq: t } })) };

// after
const excl = excludeTags.map(t => ({ tag: { eq: t } }));
const filters = excl.length > 0 ? { $not: excl } : {};
Defensive patterns

Strategy: validation

Validate before calling

function buildNotFilter(exclusions: any[]): any | undefined {
  const list = exclusions.filter(e => e && typeof e === 'object');
  return list.length > 0 ? { $not: list } : undefined;
}
const filters = buildNotFilter(excludeList) ?? {};

Type guard

const isNonEmptyNotList = (v: unknown): v is Record<string, any>[] =>
  Array.isArray(v) && v.length > 0 && v.every(i => i && typeof i === 'object' && !Array.isArray(i));

Try / catch

try { await vs.search(vec, { filters }); } catch (e) { if (e instanceof Error && e.message === '$not filter requires a non-empty list') { /* omit $not, retry */ } throw e; }

Prevention

When it happens

Trigger: filters: { $not: [] }, { $not: null }, or { $not: excludeConditions } where excludeConditions was filtered down to nothing.

Common situations: Exclusion lists computed at runtime that occasionally end up empty; merging user filter JSON with optional exclusion arrays; copy-paste of $and-style wrappers where empties slipped through.

Related errors


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