{"record":{"id":"478ac17ed185df1e","repo":"mem0ai/mem0","slug":"filter-value-for-key-r-must-be-a-scalar-str-in","errorCode":null,"errorMessage":"Filter value for {key!r} must be a scalar (str, int, float, bool), not a dict. Dicts may contain MongoDB query operators.","messagePattern":"Filter value for (.+?) must be a scalar \\(str, int, float, bool\\), not a dict\\. Dicts may contain MongoDB query operators\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"mem0/vector_stores/mongodb.py","lineNumber":154,"sourceCode":"            ids (List[str], optional): List of IDs corresponding to vectors.\n        \"\"\"\n        logger.info(f\"Inserting {len(vectors)} vectors into collection '{self.collection_name}'.\")\n\n        data = []\n        for vector, payload, _id in zip(vectors, payloads or [{}] * len(vectors), ids or [None] * len(vectors)):\n            document = {\"_id\": _id, \"embedding\": vector, \"payload\": payload}\n            data.append(document)\n        try:\n            self.collection.insert_many(data)\n            logger.info(f\"Inserted {len(data)} documents into '{self.collection_name}'.\")\n        except PyMongoError as e:\n            logger.error(f\"Error inserting data: {e}\")\n\n    @staticmethod\n    def _validate_filter_value(key: str, value: Any) -> None:\n        \"\"\"Reject values that could inject MongoDB query operators (e.g. $ne, $gt).\"\"\"\n        if isinstance(value, dict):\n            raise ValueError(\n                f\"Filter value for {key!r} must be a scalar (str, int, float, bool), \"\n                f\"not a dict. Dicts may contain MongoDB query operators.\"\n            )\n        if isinstance(value, list):\n            for item in value:\n                if isinstance(item, dict):\n                    raise ValueError(\n                        f\"Filter list for {key!r} contains a dict, \"\n                        f\"which may contain MongoDB query operators.\"\n                    )\n\n    def search(self, query: str, vectors: List[float], top_k=5, filters: Optional[Dict] = None) -> List[OutputData]:\n        \"\"\"\n        Search for similar vectors using the vector search index.\n\n        Args:\n            query (str): Query string\n            vectors (List[float]): Query vector.","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/mem0ai/mem0/blob/001c235229be8795e3834520467bd0d661ed8f34/mem0/vector_stores/mongodb.py#L136-L172","documentation":"Security guard in the MongoDB vector store's filter validation: Mem0 turns filters into MongoDB match queries, so a dict value could smuggle query operators like $ne/$gt/$where and change the query semantics (NoSQL injection). Any non-scalar dict value for a filter key is rejected before the query is built.","triggerScenarios":"Passing filters={\"user_id\": {\"$ne\": \"alice\"}} or any nested dict as a filter value to search()/list operations on the MongoDB backend; building filters from unvalidated user input that happens to be a JSON object.","commonSituations":"Frontend-supplied JSON filter objects forwarded verbatim into memory search; developers used to MongoDB's native query syntax trying to express range conditions through Mem0's filter API.","solutions":["Flatten filters to scalar equality: use one key per value (str/int/float/bool)","If you need range queries, execute them against MongoDB directly with a properly authorized client, not through Mem0's filter parameter","Sanitize user-supplied filters at your API boundary before forwarding them to Mem0"],"exampleFix":"// before\nfilters = {\"user_id\": {\"$ne\": \"alice\"}}\n\n// after\nfilters = {\"user_id\": \"alice\"}","handlingStrategy":"validation","validationCode":"def safe_filters(filters: dict) -> dict:\n    out = {}\n    for k, v in (filters or {}).items():\n        if isinstance(v, dict):\n            raise ValueError(f\"dict filter value for {k!r} not allowed\")\n        out[k] = v\n    return out\n\nfilters = safe_filters(user_supplied_filters)\nresults = store.search(query, vector, top_k, filters=filters)","typeGuard":"def is_scalar_filter_value(v) -> bool:\n    return isinstance(v, (str, int, float, bool))","tryCatchPattern":"try:\n    store.search(q, vec, filters=filters)\nexcept ValueError as e:\n    if \"MongoDB query operators\" in str(e):\n        filters = {k: v for k, v in filters.items() if not isinstance(v, dict)}\n        store.search(q, vec, filters=filters)\n    else:\n        raise","preventionTips":["Never forward raw JSON bodies as filters","Document your filter API as scalar-equality-only","Add a schema (Pydantic) for inbound filters that rejects nested objects"],"tags":["mongodb","nosql-injection","security","filters","validation"],"backgroundTag":null,"analyzedSha":"001c235229be8795e3834520467bd0d661ed8f34","analyzedAt":"2026-08-15T01:55:42.685Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}