mem0ai/mem0 · error · Error

${key} filter value must be an array.

Error message

${key} filter value must be an array.

What it means

When translating mem0 filters to OpenSearch bool queries, the logical combinators AND/OR/NOT must each hold an array of nested filter objects so they can be flat-mapped into sub-clauses. A non-array value (single object or scalar) cannot be expanded, so the builder throws naming the offending combinator key.

Source

Thrown at mem0-ts/src/oss/src/vector_stores/opensearch.ts:518

    const normalized: Record<string, any> = {};
    for (const [key, value] of Object.entries(filters)) {
      normalized[KEY_MAP[key] || key] = value;
    }

    return Object.entries(normalized)
      .map(([key, value]) => this.buildFilterClause(key, value))
      .filter((clause): clause is Record<string, any> => Boolean(clause));
  }

  private buildFilterClause(
    key: string,
    value: any,
  ): Record<string, any> | null {
    if (value === null || value === undefined) return null;

    if (key === "AND" || key === "OR" || key === "NOT") {
      if (!Array.isArray(value)) {
        throw new Error(`${key} filter value must be an array.`);
      }

      const clauses = value
        .flatMap((filter) => this.buildFilterClauses(filter))
        .filter(Boolean);

      if (clauses.length === 0) return null;

      if (key === "AND") {
        return { bool: { filter: clauses } };
      }
      if (key === "OR") {
        return { bool: { should: clauses, minimum_should_match: 1 } };
      }
      return { bool: { must_not: clauses } };
    }

    if (value === "*") {

View on GitHub (pinned to 001c235229)

Solutions

  1. Wrap combinator values in arrays: { AND: [ { user_id: 'a' } ] }, { OR: [ ... ] }, { NOT: [ ... ] }.
  2. If porting from $and/$or/$not style, also rename keys to uppercase AND/OR/NOT for this backend.
  3. Centralize filter construction in one helper that always emits arrays for combinators.

Example fix

// before
{ NOT: { run_id: 'old' } }

// after
{ NOT: [ { run_id: 'old' } ] }
Defensive patterns

Strategy: validation

Validate before calling

for (const k of ['AND', 'OR', 'NOT']) {
  if (k in filters && !Array.isArray((filters as any)[k])) {
    (filters as any)[k] = [(filters as any)[k]]; // normalize
  }
}

Type guard

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

Prevention

When it happens

Trigger: Passing filters such as { AND: { user_id: 'a' } }, { OR: 'x' }, or { NOT: { run_id: 'y' } } to keywordSearch/vector search/list on the OpenSearch store.

Common situations: Filters authored for the Python SDK or Neptune backend using $and/$or/$not lowercase single objects and partially converted; dynamic filter assembly forgetting the array; JSON configs that drop single-element arrays.

Related errors


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