mem0ai/mem0 · error · Error

Unsupported filter operator: ${op}

Error message

Unsupported filter operator: ${op}

What it means

When a pgvector SearchFilters value is an object, each key inside it is treated as a comparison operator and looked up in OPERATOR_SQL_MAP. An operator not present in that map throws 'Unsupported filter operator'. Supported operators are those mapped for SQL (eq, ne, gt, gte, lt, lte, in, nin, contains, icontains, etc.).

Source

Thrown at mem0-ts/src/oss/src/vector_stores/pgvector.ts:118

        conditions.push("NOT (" + notGroups.join(" OR ") + ")");
      }
      continue;
    }

    const safeKey = escapeFilterKey(key);

    if (value === "*") {
      conditions.push(`payload ? $${paramIndex}`);
      values.push(key);
      paramIndex++;
      continue;
    }

    if (typeof value === "object" && value !== null && !Array.isArray(value)) {
      for (const [op, opValue] of Object.entries(value)) {
        const mapping = OPERATOR_SQL_MAP[op];
        if (!mapping) {
          throw new Error(`Unsupported filter operator: ${op}`);
        }
        const clause = mapping.template
          .replace("%KEY%", safeKey)
          .replace("%IDX%", String(paramIndex));
        conditions.push(clause);

        if (op === "in" || op === "nin") {
          values.push((opValue as any[]).map(String));
        } else if (op === "contains" || op === "icontains") {
          const escaped = String(opValue)
            .replace(/\\/g, "\\\\")
            .replace(/%/g, "\\%")
            .replace(/_/g, "\\_");
          values.push(`%${escaped}%`);
        } else if (mapping.numeric) {
          values.push(Number(opValue));
        } else {
          values.push(String(opValue));

View on GitHub (pinned to 001c235229)

Solutions

  1. Correct the operator name to a supported one: eq, ne, gt, gte, lt, lte, in, nin, contains, icontains
  2. Remove the $ prefix if using Mongo-style operators ('$gte' -> 'gte')
  3. For operators like 'between', rewrite as two range conditions combined with AND

Example fix

// before
const r = await vs.search(embedding, { filters: { ts: { $gte: 5 } } });

// after
const r = await vs.search(embedding, { filters: { ts: { gte: 5 } } });
Defensive patterns

Strategy: validation

Validate before calling

const SUPPORTED = new Set(['eq','ne','gt','gte','lt','lte','in','nin','contains','icontains']);
function validateOperators(filters: any): void {
  for (const v of Object.values(filters ?? {})) {
    if (v && typeof v === 'object' && !Array.isArray(v)) {
      for (const op of Object.keys(v)) {
        if (!SUPPORTED.has(op)) throw new Error(`Unsupported operator: ${op}`);
      }
    }
  }
}
validateOperators(filters);

Type guard

const isSupportedOperator = (op: string): op is 'eq'|'ne'|'gt'|'gte'|'lt'|'lte'|'in'|'nin'|'contains'|'icontains' =>
  ['eq','ne','gt','gte','lt','lte','in','nin','contains','icontains'].includes(op);

Try / catch

try { await vs.search(vec, { filters }); } catch (e) { if (e instanceof Error && e.message.startsWith('Unsupported filter operator')) { /* strip/replace bad op, retry once */ } throw e; }

Prevention

When it happens

Trigger: Passing a nested operator object with a typo or unsupported operator, e.g. filters: { ts: { gteq: 5 } }, { tag: { has: 'x' } }, or { f: { between: [1,2] } } — any object-valued filter whose keys are not recognized comparison operators.

Common situations: Typos like 'gteq' or 'lteq'; copying filter syntax from another vector DB (Qdrant/Weaviate style operators) into the pgvector store; assuming Mongo-style '$gte' works here.

Related errors


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