{"record":{"id":"e76f35b8cb0fd0bf","repo":"mem0ai/mem0","slug":"not-filter-value-must-be-a-list-of-filter-dicts-g-e76f35","errorCode":null,"errorMessage":"NOT filter value must be a list of filter dicts, got ${typeof value}","messagePattern":"NOT filter value must be a list of filter dicts, got (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"mem0-ts/src/oss/src/vector_stores/memory.ts","lineNumber":203,"sourceCode":"        // All conditions must match\n        const allMatch = value.every((sub: SearchFilters) =>\n          this.filterVector(vector, sub),\n        );\n        if (!allMatch) return false;\n      } else if (key === \"OR\") {\n        if (!Array.isArray(value)) {\n          throw new Error(\n            `OR filter value must be a list of filter dicts, got ${typeof value}`,\n          );\n        }\n        // At least one condition must match\n        const anyMatch = value.some((sub: SearchFilters) =>\n          this.filterVector(vector, sub),\n        );\n        if (!anyMatch) return false;\n      } else if (key === \"NOT\") {\n        if (!Array.isArray(value)) {\n          throw new Error(\n            `NOT filter value must be a list of filter dicts, got ${typeof value}`,\n          );\n        }\n        // None of the conditions should match\n        const noneMatch = value.every(\n          (sub: SearchFilters) => !this.filterVector(vector, sub),\n        );\n        if (!noneMatch) return false;\n      } else {\n        // Regular field condition\n        if (!this.matchFieldCondition(vector.payload, key, value)) {\n          return false;\n        }\n      }\n    }\n\n    return true;\n  }","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/mem0ai/mem0/blob/001c235229be8795e3834520467bd0d661ed8f34/mem0-ts/src/oss/src/vector_stores/memory.ts#L185-L221","documentation":"The NOT logical operator in the SQLite MemoryVectorStore expects an array of filter dicts; each sub-condition is evaluated and the vector passes only if none match (every(sub => !filterVector(...))). A non-array value cannot be iterated, so the store throws rather than guessing semantics.","triggerScenarios":"search(query, topK, { NOT: { user_id: 'u1' } }) instead of { NOT: [{ user_id: 'u1' }] }; copy-pasting an AND/OR shape into NOT without adjusting the value type.","commonSituations":"Exclusion filters written inline; refactors that change one logical operator but keep the operand shape; mixed AND/NOT nested objects where the nested NOT value is a dict.","solutions":["Wrap in an array: { NOT: [{ user_id: 'u1' }] }.","Combine exclusions: { AND: [{ run_id: 'r1' }, ...], NOT: [{ user_id: 'blocked' }] }.","Write a small normalizeFilters() helper that wraps bare objects under AND/OR/NOT keys."],"exampleFix":"// before\nstore.search(q, 5, { NOT: { user_id: 'u1' } }); // throws\n\n// after\nstore.search(q, 5, { NOT: [{ user_id: 'u1' }] });","handlingStrategy":"validation","validationCode":"if (filters.NOT !== undefined && !Array.isArray(filters.NOT)) {\n  filters = { ...filters, NOT: [filters.NOT] };\n}","typeGuard":"const isFilterList = (v: unknown): v is SearchFilters[] =>\n  Array.isArray(v) && v.every((e) => e && typeof e === 'object' && !Array.isArray(e));","tryCatchPattern":"try { await store.search(q, 5, filters); }\ncatch (e) {\n  if (e instanceof Error && e.message.startsWith('NOT filter value')) {\n    // fix shape and retry once\n    return store.search(q, 5, { ...filters, NOT: [filters.NOT] });\n  }\n  throw e;\n}","preventionTips":["Treat AND/OR/NOT uniformly: value is always SearchFilters[].","Write exclusion filters as { NOT: [{ field: value }] } from the start.","Guard dynamically-built filter trees with a shape validator before search()."],"tags":["filters","sqlite","vector-store","validation","typescript"],"backgroundTag":null,"analyzedSha":"001c235229be8795e3834520467bd0d661ed8f34","analyzedAt":"2026-08-15T01:55:42.685Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}