mem0ai/mem0 · error · ValueError

Filter value for {key!r} must be str, int, float, or bool, g

Error message

Filter value for {key!r} must be str, int, float, or bool, got {type(value).__name__}

What it means

ValueError from _validate_filter in elasticsearch.py when a filter value is not str, int, float, or bool. The value is placed directly into the ES term query, so unrenderable types (None, list, dict, datetime) are rejected up front rather than producing a malformed query or a confusing server error.

Source

Thrown at mem0/vector_stores/elasticsearch.py:32

from mem0.vector_stores.base import VectorStoreBase

logger = logging.getLogger(__name__)


class OutputData(BaseModel):
    id: str
    score: float
    payload: Dict


_SAFE_FILTER_KEY = re.compile(r"^[a-zA-Z_][a-zA-Z0-9_]*$")


def _validate_filter(key: str, value: Any) -> None:
    if not isinstance(key, str) or not _SAFE_FILTER_KEY.match(key):
        raise ValueError(f"Invalid filter key: {key!r}")
    if not isinstance(value, (str, int, float, bool)):
        raise ValueError(
            f"Filter value for {key!r} must be str, int, float, or bool, "
            f"got {type(value).__name__}"
        )


class ElasticsearchDB(VectorStoreBase):
    def __init__(self, **kwargs):
        config = ElasticsearchConfig(**kwargs)

        # Initialize Elasticsearch client
        if config.cloud_id:
            self.client = Elasticsearch(
                cloud_id=config.cloud_id,
                api_key=config.api_key,
                verify_certs=config.verify_certs,
                ca_certs=config.ca_certs,
                headers= config.headers or {},
            )

View on GitHub (pinned to 001c235229)

Solutions

  1. Omit keys whose value is None: {k: v for k, v in filters.items() if v is not None}.
  2. Convert datetimes to strings and flatten lists to a single scalar or repeated equality terms as supported.
  3. For range queries, pre-compute a boolean/bucketed field because only equality filtering is supported here.

Example fix

# before
db.search(query, vectors, filters={"since": {"gte": "2024-01-01"}})  # ValueError: got dict

# after
filters = {"user_id": "alice"}  # scalars only; convert/remove the rest
db.search(query, vectors, filters=filters)
Defensive patterns

Strategy: type-guard

Validate before calling

def scalarize_filters(filters: dict) -> dict:
    out = {}
    for k, v in (filters or {}).items():
        if v is None:
            continue
        if hasattr(v, "isoformat"):
            v = v.isoformat()
        if not isinstance(v, (str, int, float, bool)):
            raise ValueError(f"filter {k!r} must be scalar, got {type(v).__name__}")
        out[k] = v
    return out

db.search(query, vectors, filters=scalarize_filters(filters))

Type guard

def is_scalar_filter_value(v) -> bool:
    return isinstance(v, (str, int, float, bool)) and not hasattr(v, "isoformat")

Prevention

When it happens

Trigger: search/get with filters={'role': None}, {'tags': ['a']}, {'ts': datetime.now()}, or nested operator dicts ({'gte': 1}). bool is accepted (subclass of int); None is not.

Common situations: Optional filters left as None instead of omitted; passing range/query DSL fragments from other libraries; datetime objects not converted to ISO strings.

Related errors


AI-assisted analysis of mem0ai/mem0@001c235229 (2026-08-15). Data as JSON: /api/errors/1ee0505b9b73dd3e. Report an issue: GitHub.