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
- Flatten to plain equality values: { user_id: 'u1', score: 5, active: true }.
- For multiple allowed values, issue one search per value and merge results (no $in support here).
- 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
- Milvus filters here are equality-only AND-combined; don't pass Mongo-style operators or arrays.
- Type filter payloads as Record<string, string | number | boolean> in your call sites.
- Validate external/LLM-generated filter JSON against that scalar schema.
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
- AND filter value must be a list of filter dicts, got ${typeo
- OR filter value must be a list of filter dicts, got ${typeof
- NOT filter value must be a list of filter dicts, got ${typeo
- AND filter value must be a list of filter dicts, got ${typeo
- OR filter value must be a list of filter dicts, got ${typeof
AI-assisted analysis of mem0ai/mem0@001c235229 (2026-08-15).
Data as JSON: /api/errors/a98218ff8291b8a4.
Report an issue: GitHub.