mem0ai/mem0 · error · Error
Filter value for '${key}' must be a string, number, or boole
Error message
Filter value for '${key}' must be a string, number, or boolean, got ${Array.isArray(value) ? "an array" : "an object"}. What it means
Filter leaf values become OpenSearch term/terms/range/wildcard query parameters. Accepting arbitrary objects would let a caller inject raw query DSL (e.g. a term object with boost or case_insensitive, changing query semantics or exfiltrating internals), so the store enforces a scalar allow-list (string/number/boolean/null) mirroring the Python SDK's _validate_filter. Non-scalar leaves throw with the offending key and actual type.
Source
Thrown at mem0-ts/src/oss/src/vector_stores/opensearch.ts:640
return clauses.length === 1 ? clauses[0] : { bool: { filter: clauses } };
}
private payloadField(key: string, keyword: boolean): string {
if (key.startsWith("payload.")) {
return keyword && !key.endsWith(".keyword") ? `${key}.keyword` : key;
}
const field = `payload.${key}`;
return keyword ? `${field}.keyword` : field;
}
// Filter values become OpenSearch term/terms/range/wildcard leaves. Allowing
// an object here lets a caller inject raw query parameters (e.g. a `term`
// object form with `boost`/`case_insensitive`), so reject non-scalar leaves.
// Mirrors the Python SDK's `_validate_filter` scalar allow-list (PR #5986).
private assertScalarValue(key: string, value: any): void {
if (value !== null && typeof value === "object") {
throw new Error(
`Filter value for '${key}' must be a string, number, or boolean, got ` +
`${Array.isArray(value) ? "an array" : "an object"}.`,
);
}
}
private assertScalarArray(key: string, value: any): void {
if (!Array.isArray(value)) {
throw new Error(`Filter value for '${key}' must be an array.`);
}
value.forEach((item) => this.assertScalarValue(key, item));
}
}
View on GitHub (pinned to 001c235229)
Solutions
- Pass plain scalars for scalar operators: { user_id: 'a' } or { memory: { contains: 'text' } }.
- For membership use the dedicated in operator with an array: { tag: { in: ['a','b'] } } — do not inline DSL objects.
- Validate external filter input against a schema (zod/etc.) before handing it to search.
Example fix
// before
filters = { user_id: { value: 'alice', boost: 2 } };
// after
filters = { user_id: 'alice' }; Defensive patterns
Strategy: type-guard
Validate before calling
for (const [field, ops] of Object.entries(fieldFilters)) {
for (const [op, v] of Object.entries(ops || {})) {
if (v !== null && typeof v === 'object' && !['in','nin'].includes(op)) {
throw new TypeError(`Field '${field}' operator '${op}' expects a scalar`);
}
}
} Type guard
const isScalar = (v: unknown): v is string | number | boolean | null => v === null || ['string', 'number', 'boolean'].includes(typeof v);
Prevention
- Pass plain scalars; never inline OpenSearch DSL in filters
- Schema-validate user-supplied filters (zod)
- Use the in operator for arrays instead of raw terms objects
When it happens
Trigger: Passing { user_id: { term: { value: 'a', boost: 2 } } } or any object/array where a scalar is expected, e.g. { user_id: ['a','b'] } where the operator expects a scalar (contains, eq).
Common situations: Attempts to hand-tune OpenSearch relevance via query DSL inside filters; accidentally passing an array to a scalar operator; filters built from unvalidated user input where a client sends an object.
Related errors
- Invalid filter key: {key!r}
- Filter value for {key!r} must be str, int, float, or bool, g
- Filter list for '${key}' contains an object, which may conta
- Filter value for '${key}' must be a scalar (string, number,
- ${key} filter value must be an array.
AI-assisted analysis of mem0ai/mem0@001c235229 (2026-08-15).
Data as JSON: /api/errors/72f148f64a6cfe85.
Report an issue: GitHub.