run-llama/llama_index · error · TypeError

Both metadata_value and value should be strings to be used w

Error message

Both metadata_value and value should be strings to be used with a TEXT_MATCH filter

What it means

Inside `build_metadata_filter_fn`'s operator dispatch, FilterOperator.TEXT_MATCH performs substring containment, which is only defined for strings. If either the filter's `value` or the stored `metadata_value` is not a str (int, list, None...), the code raises TypeError instead of attempting the comparison. This is a per-node-type guard: it fires during query-time filtering when types do not line up.

Source

Thrown at llama-index-core/llama_index/core/vector_stores/utils.py:141

                return metadata_value != value
            if operator == FilterOperator.GT:
                return metadata_value > value
            if operator == FilterOperator.GTE:
                return metadata_value >= value
            if operator == FilterOperator.LT:
                return metadata_value < value
            if operator == FilterOperator.LTE:
                return metadata_value <= value
            if operator == FilterOperator.IN:
                return metadata_value in value
            if operator == FilterOperator.NIN:
                return metadata_value not in value
            if operator == FilterOperator.CONTAINS:
                return value in metadata_value
            if operator == FilterOperator.TEXT_MATCH:
                if isinstance(value, str) and isinstance(metadata_value, str):
                    return value in metadata_value
                raise TypeError(
                    "Both metadata_value and value should be strings to be used with a "
                    "TEXT_MATCH filter"
                )
            if operator == FilterOperator.TEXT_MATCH_INSENSITIVE:
                if isinstance(value, str) and isinstance(metadata_value, str):
                    return value.lower() in metadata_value.lower()
                raise TypeError(
                    "Both metadata_value and value should be strings to be used with a "
                    "TEXT_MATCH_INSENSITIVE filter"
                )
            if operator == FilterOperator.ALL:
                return all(val in metadata_value for val in value)
            if operator == FilterOperator.ANY:
                return any(val in metadata_value for val in value)

            raise ValueError(f"Invalid operator: {operator}")

        metadata = metadata_lookup_fn(node_id)

View on GitHub (pinned to afd0fef371)

Solutions

  1. Use the right operator: `FilterOperator.EQ` for exact numeric matches, `TEXT_MATCH` only for string fields.
  2. Coerce the filter value: `str(value)` when the field is genuinely textual.
  3. Normalize the stored metadata to a consistent type at ingestion time (e.g. always store year as str).
  4. Guard the query: check `isinstance(filter.value, str)` before issuing a TEXT_MATCH filter.

Example fix

# before
f = MetadataFilter(key="title", value=42, operator=FilterOperator.TEXT_MATCH)

# after
f = MetadataFilter(key="title", value="42", operator=FilterOperator.TEXT_MATCH)
# or exact numeric match:
f = MetadataFilter(key="page", value=42, operator=FilterOperator.EQ)
Defensive patterns

Strategy: type-guard

Validate before calling

from llama_index.core.vector_stores import FilterOperator

def text_match_filter_valid(value) -> bool:
    return isinstance(value, str)

Type guard

def is_text_match_safe(filter_, sample_metadata: dict) -> bool:
    if filter_.operator is not FilterOperator.TEXT_MATCH:
        return True
    stored = sample_metadata.get(filter_.key)
    return isinstance(filter_.value, str) and isinstance(stored, str)

Try / catch

try:
    result = store.query(query)
except TypeError as e:
    if "TEXT_MATCH" in str(e):
        raise ValueError("TEXT_MATCH requires str value and str metadata field") from e
    raise

Prevention

When it happens

Trigger: Building a MetadataFilter with `operator=FilterOperator.TEXT_MATCH` and a non-string value (e.g. an int id), or querying where the metadata field keyed by `filter.key` holds a number/list/None in some nodes; used with SimpleVectorStore or any store that evaluates filters client-side via this function.

Common situations: Numeric fields (year, page) mistakenly filtered with TEXT_MATCH instead of EQ/GTE; metadata schemas that changed type over time (some docs store year as int, others as str); None values from optional fields; JSON ingestion that yields numbers where strings were expected.

Related errors


AI-assisted analysis of run-llama/llama_index@afd0fef371 (2026-08-15). Data as JSON: /api/errors/ff2203b9f7ad41db. Report an issue: GitHub.