mem0ai/mem0 · error · Error

Filter value for ${JSON.stringify(key)} must be a string, nu

Error message

Filter value for ${JSON.stringify(key)} must be a string, number, or boolean, got ${typeof value}

What it means

Milvus scalar equality expressions can only compare metadata fields against string, number, or boolean literals; the filter builder emits quoted strings or raw numbers/booleans and rejects everything else (objects, arrays, null is skipped earlier, symbols, undefined handled earlier). Passing e.g. { user_id: { $eq: 'u1' } } or an array value throws with the actual typeof so the caller can fix the shape.

Source

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

      if (!Milvus.SAFE_FILTER_KEY.test(key)) {
        throw new Error(`Invalid filter key: ${JSON.stringify(key)}`);
      }
      if (value === "*") {
        // Wildcard - match any value. Milvus has no direct wildcard, so skip
        // the clause rather than emitting a literal `== "*"` that matches
        // nothing. Mirrors the Python provider (#6187) and the chroma/pinecone
        // stores.
        continue;
      }
      if (typeof value === "string") {
        // Escape backslashes before quotes so a value can't break out of the
        // string literal (order matters, exactly as in the Python provider).
        const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
        operands.push(`(metadata["${key}"] == "${escaped}")`);
      } else if (typeof value === "number" || typeof value === "boolean") {
        operands.push(`(metadata["${key}"] == ${value})`);
      } else {
        throw new Error(
          `Filter value for ${JSON.stringify(key)} must be a string, number, or boolean, got ${typeof value}`,
        );
      }
    }
    return operands.length > 0 ? operands.join(" and ") : undefined;
  }

  /**
   * Text fed to the BM25 sparse index for a payload. Prefers `textLemmatized`,
   * then `text_lemmatized`, then raw `data`; truncates to the VarChar limit.
   */
  private bm25Text(payload?: Record<string, any>): string {
    if (!payload) return "";
    const raw =
      payload.textLemmatized || payload.text_lemmatized || payload.data || "";
    return String(raw).slice(0, 65535);
  }

View on GitHub (pinned to 001c235229)

Solutions

  1. Flatten to plain equality values: { user_id: 'u1', score: 5, active: true }.
  2. For multiple allowed values, issue one search per value and merge results (no $in support here).
  3. For range/operator semantics, use a different provider or filter results client-side after search.

Example fix

// before
store.search(q, 5, { user_id: { $eq: 'u1' } }); // typeof value === 'object' -> throws

// after
store.search(q, 5, { user_id: 'u1' });
Defensive patterns

Strategy: type-guard

Validate before calling

for (const [k, v] of Object.entries(filters || {})) {
  if (v !== undefined && v !== null && v !== '*' && !['string', 'number', 'boolean'].includes(typeof v)) {
    throw new Error(`Milvus filter '${k}' must be scalar, got ${typeof v}`);
  }
}

Type guard

type MilvusFilterValue = string | number | boolean;
const isMilvusFilterValue = (v: unknown): v is MilvusFilterValue =>
  typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean';

Try / catch

try { await store.search(q, 5, filters); }
catch (e) {
  if (e instanceof Error && /must be a string, number, or boolean/.test(e.message)) {
    // flatten operator objects ({ $eq: x } -> x) and retry
  } else throw e;
}

Prevention

When it happens

Trigger: Passing Mongo-style operator objects ({ user_id: { $in: [...] } }) to the Milvus store; reusing a filter built for the memory.ts/other stores that accept richer shapes; sending { tag: ['a','b'] } (arrays are unsupported, unlike some other providers).

Common situations: Writing provider-agnostic filter code and forgetting Milvus is equality-only AND-combined; filters deserialized from JSON APIs where a value silently became an object.

Related errors


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