{"record":{"id":"205b63eaf0dae56c","repo":"mem0ai/mem0","slug":"key-filter-value-must-be-an-array","errorCode":null,"errorMessage":"${key} filter value must be an array.","messagePattern":"(.+?) filter value must be an array\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"mem0-ts/src/oss/src/vector_stores/neptune_analytics.ts","lineNumber":493,"sourceCode":"      conditions.push(metadataFilter);\n    }\n\n    return this.combineVertexFilters(\"andAll\", conditions)!;\n  }\n\n  private buildMetadataVertexFilter(\n    filters?: SearchFilters,\n  ): NeptuneVertexFilter | undefined {\n    const operations: NeptuneVertexFilter[] = [];\n\n    for (const [key, value] of Object.entries(filters || {})) {\n      if (value === undefined) {\n        continue;\n      }\n\n      if (key === \"$and\" || key === \"$or\") {\n        if (!Array.isArray(value)) {\n          throw new Error(`${key} filter value must be an array.`);\n        }\n\n        const nested = value\n          .map((entry) => this.buildMetadataVertexFilter(entry))\n          .filter((entry): entry is NeptuneVertexFilter => !!entry);\n        const joiner = key === \"$and\" ? \"andAll\" : \"orAll\";\n        const combined = this.combineVertexFilters(joiner, nested);\n        if (combined) {\n          operations.push(combined);\n        }\n        continue;\n      }\n\n      if (key === \"$not\") {\n        if (!Array.isArray(value)) {\n          throw new Error(\"$not filter value must be an array.\");\n        }\n","sourceCodeStart":475,"sourceCodeEnd":511,"githubUrl":"https://github.com/mem0ai/mem0/blob/001c235229be8795e3834520467bd0d661ed8f34/mem0-ts/src/oss/src/vector_stores/neptune_analytics.ts#L475-L511","documentation":"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.","triggerScenarios":"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.","commonSituations":"Assuming $and takes a dict (Mongo-influenced mental model); reusing filter shapes across providers; LLM-generated filter JSON with inconsistent nesting.","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."],"exampleFix":"// before\nstore.search(q, 5, { $and: { user_id: 'u1', run_id: 'r1' } }); // throws\n\n// after\nstore.search(q, 5, { $and: [{ user_id: 'u1' }, { run_id: 'r1' }] });","handlingStrategy":"validation","validationCode":"for (const k of ['$and', '$or']) {\n  if (filters[k] !== undefined && !Array.isArray(filters[k])) filters[k] = [filters[k]];\n}","typeGuard":"type NeptuneFilters = Record<string, unknown> & { $and?: NeptuneFilters[]; $or?: NeptuneFilters[]; $not?: NeptuneFilters[] };\nconst isNeptuneFilterArray = (v: unknown): v is NeptuneFilters[] => Array.isArray(v);","tryCatchPattern":"try { await store.search(q, 5, filters); }\ncatch (e) {\n  if (e instanceof Error && /\\$and|\\$or filter value must be an array/.test(e.message)) {\n    return store.search(q, 5, wrapLogicalKeys(filters)); // wrap and retry once\n  }\n  throw e;\n}","preventionTips":["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."],"tags":["neptune","filters","validation","vector-store","aws"],"backgroundTag":null,"analyzedSha":"001c235229be8795e3834520467bd0d661ed8f34","analyzedAt":"2026-08-15T01:55:42.685Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}