mem0ai/mem0 · error · Error
${key} filter value must be an array.
Error message
${key} filter value must be an array. What it means
buildMetadataVertexFilter() translates $and/$or keys into Neptune's andAll/orAll filter combinators, which take arrays of nested filters. If the value under $and or $or is not an array (a single filter object, a scalar), the recursive .map over sub-entries is impossible, so the store throws before building the vertex filter.
Source
Thrown at mem0-ts/src/oss/src/vector_stores/neptune_analytics.ts:493
conditions.push(metadataFilter);
}
return this.combineVertexFilters("andAll", conditions)!;
}
private buildMetadataVertexFilter(
filters?: SearchFilters,
): NeptuneVertexFilter | undefined {
const operations: NeptuneVertexFilter[] = [];
for (const [key, value] of Object.entries(filters || {})) {
if (value === undefined) {
continue;
}
if (key === "$and" || key === "$or") {
if (!Array.isArray(value)) {
throw new Error(`${key} filter value must be an array.`);
}
const nested = value
.map((entry) => this.buildMetadataVertexFilter(entry))
.filter((entry): entry is NeptuneVertexFilter => !!entry);
const joiner = key === "$and" ? "andAll" : "orAll";
const combined = this.combineVertexFilters(joiner, nested);
if (combined) {
operations.push(combined);
}
continue;
}
if (key === "$not") {
if (!Array.isArray(value)) {
throw new Error("$not filter value must be an array.");
}
View on GitHub (pinned to 001c235229)
Solutions
- Use arrays: { $and: [{ user_id: 'u1' }, { run_id: 'r1' }] }.
- For plain conjunction just put fields side by side: { user_id: 'u1', run_id: 'r1' } (implicitly ANDed).
- Validate the $-tree shape (arrays under $and/$or/$not) before calling search.
Example fix
// before
store.search(q, 5, { $and: { user_id: 'u1', run_id: 'r1' } }); // throws
// after
store.search(q, 5, { $and: [{ user_id: 'u1' }, { run_id: 'r1' }] }); Defensive patterns
Strategy: validation
Validate before calling
for (const k of ['$and', '$or']) {
if (filters[k] !== undefined && !Array.isArray(filters[k])) filters[k] = [filters[k]];
} Type guard
type NeptuneFilters = Record<string, unknown> & { $and?: NeptuneFilters[]; $or?: NeptuneFilters[]; $not?: NeptuneFilters[] };
const isNeptuneFilterArray = (v: unknown): v is NeptuneFilters[] => Array.isArray(v); Try / catch
try { await store.search(q, 5, filters); }
catch (e) {
if (e instanceof Error && /\$and|\$or filter value must be an array/.test(e.message)) {
return store.search(q, 5, wrapLogicalKeys(filters)); // wrap and retry once
}
throw e;
} Prevention
- Every $and/$or/$not node's value is an array of filter objects — enforce with a recursive validator.
- Plain adjacent fields are already ANDed; skip $and for simple conjunctions.
- Unit-test nested filter trees against the Neptune provider.
When it happens
Trigger: search(q, k, { $and: { user_id: 'u1', run_id: 'r1' } }) instead of { $and: [{ user_id: 'u1' }, { run_id: 'r1' }] }; filters received from JSON where the array was collapsed; mixing $-prefixed keys (Neptune style) with the AND style of other providers.
Common situations: Assuming $and takes a dict (Mongo-influenced mental model); reusing filter shapes across providers; LLM-generated filter JSON with inconsistent nesting.
Related errors
- $not filter value must be an array.
- Unsupported Neptune Analytics filter operator: ${operator}
- Invalid filter key: {key!r}
- Filter value for {key!r} must be str, int, float, or bool, g
- AND filter value must be a list of filter dicts, got ${typeo
AI-assisted analysis of mem0ai/mem0@001c235229 (2026-08-15).
Data as JSON: /api/errors/205b63eaf0dae56c.
Report an issue: GitHub.