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

Milvus._create_filter() only accepts filter values of str, int, float, bool, or the '*' wildcard; anything else (list, dict, None, tuple) cannot be rendered into the metadata["key"] == <literal> expression and raises ValueError.

Source

Thrown at mem0/vector_stores/milvus.py:171

            filters (dict): filters [user_id, agent_id, run_id]

        Returns:
            str: formated filter.
        """
        operands = []
        for key, value in filters.items():
            if not self._SAFE_FILTER_KEY.match(key):
                raise ValueError(f"Invalid filter key: {key!r}")
            if value == "*":
                # Wildcard - match any value (MilvusDB doesn't have direct wildcard, so we skip this filter)
                continue
            elif isinstance(value, str):
                escaped = value.replace("\\", "\\\\").replace('"', '\\"')
                operands.append(f'(metadata["{key}"] == "{escaped}")')
            elif isinstance(value, (int, float, bool)):
                operands.append(f'(metadata["{key}"] == {value})')
            else:
                raise ValueError(
                    f"Filter value for {key!r} must be str, int, float, or bool, "
                    f"got {type(value).__name__}"
                )

        return " and ".join(operands)

    def _parse_output(self, data: list):
        """
        Parse the output data.

        Args:
            data (Dict): Output data.

        Returns:
            List[OutputData]: Parsed output data.
        """
        memory = []

View on GitHub (pinned to 001c235229)

Solutions

  1. Flatten list values into multiple searches (one per value) and merge results, since only equality is supported
  2. Remove None/nested values from the filters dict before calling search
  3. Use '*' only as a bare string value meaning match-any (it is skipped)

Example fix

# before
filters = {'user_id': ['u1', 'u2']}  # ValueError: must be str, int, float, or bool
results = m.search('q', filters=filters)

# after
results = []
for uid in ['u1', 'u2']:
    results.extend(m.search('q', filters={'user_id': uid}))
Defensive patterns

Strategy: validation

Validate before calling

def coerce_filters(filters):
    out = {}
    for k, v in (filters or {}).items():
        if v is None or isinstance(v, (list, tuple, dict, set)):
            continue  # unsupported value type: skip or explode lists upstream
        out[k] = v
    return out

Type guard

def is_supported_filter_value(v) -> bool:
    return isinstance(v, (str, int, float, bool)) and not isinstance(v, (list, dict))

Try / catch

try:
    m.search('query', filters=filters)
except ValueError as e:
    if 'must be str, int, float, or bool' in str(e):
        filters = coerce_filters(filters)
        results = m.search('query', filters=filters)
    else:
        raise

Prevention

When it happens

Trigger: Passing filters={'user_id': ['u1','u2']} (IN-style list), {'run_id': None}, or a nested dict as a value — mem0's Milvus filter builder has no operator syntax, only equality.

Common situations: Porting filters from Qdrant/other stores that support list membership (match any); forgetting that mem0 search filters are equality-only; '*' wildcard misuse as a dict value.

Related errors


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