RyanCodrai/turbovec · error · TypeError
Both metadata value and filter value must be strings for the
Error message
Both metadata value and filter value must be strings for the TEXT_MATCH operator
What it means
TEXT_MATCH requires both the metadata value and the filter value to be strings so substring semantics are well-defined. The reference implementation raises AttributeError on non-strings (llama_index issue #302); this library raises a clearer TypeError instead.
Source
Thrown at turbovec-python/python/turbovec/llama_index.py:764
return value >= target
if op == FilterOperator.LTE:
return value <= target
if op == FilterOperator.IN:
return value in target
if op == FilterOperator.NIN:
return value not in target
if op == FilterOperator.CONTAINS:
return target in value
if op == FilterOperator.TEXT_MATCH:
# Case-SENSITIVE substring. `FilterOperator` defines
# TEXT_MATCH and TEXT_MATCH_INSENSITIVE as distinct operators,
# so folding case here would collapse that distinction and
# leave no way to ask for a case-sensitive match. The type
# guard is ours: the reference raises AttributeError on a
# non-string (issue #302).
if isinstance(target, str) and isinstance(value, str):
return target in value
raise TypeError(
"Both metadata value and filter value must be strings "
"for the TEXT_MATCH operator"
)
if _TEXT_MATCH_INSENSITIVE is not None and op == _TEXT_MATCH_INSENSITIVE:
if isinstance(target, str) and isinstance(value, str):
return target.lower() in value.lower()
raise TypeError(
"Both metadata value and filter value must be strings "
"for the TEXT_MATCH_INSENSITIVE operator"
)
if op == FilterOperator.ALL:
# Reference (`utils.py:152-153`): every element of `target`
# must be present in the metadata value (which is typically
# a list — tag-set matching).
return all(t in value for t in target)
if op == FilterOperator.ANY:
return any(t in value for t in target)
raise NotImplementedError(View on GitHub (pinned to ccab9f325e)
Solutions
- Convert the metadata field to a string at ingestion time (store it as str)
- Convert the filter value to a string: FilterValue=str(123)
- Use a numeric operator (EQ/GT) instead of TEXT_MATCH for non-string fields
Example fix
// before MetadataFilter(key="count", value=5, operator=FilterOperator.TEXT_MATCH) // after MetadataFilter(key="count", value="5", operator=FilterOperator.TEXT_MATCH)
Defensive patterns
Strategy: type-guard
Validate before calling
if op == FilterOperator.TEXT_MATCH and not (isinstance(meta_val, str) and isinstance(filt_val, str)):
raise TypeError("TEXT_MATCH requires string metadata and filter values") Type guard
def text_match_safe(meta_val, filt_val) -> bool:
return isinstance(meta_val, str) and isinstance(filt_val, str) and meta_val in filt_val Try / catch
try:
store.query(q)
except TypeError as e:
if "TEXT_MATCH operator" in str(e):
coerce_filter_values_to_str(q.filters)
store.query(q)
else:
raise Prevention
- Store metadata fields that will be text-matched as strings
- Coerce filter values with str() when building filters
- Validate filter value types against the metadata schema
When it happens
Trigger: Querying with FilterOperator.TEXT_MATCH where the stored metadata field is a number/bool/list or the filter value is a non-string.
Common situations: Numeric fields (ids, counts) queried with TEXT_MATCH; forgetting str() conversion on the filter value; metadata schema drift after a pipeline change.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Both metadata value and filter value must be strings for the
- filter condition {condition!r} not supported by TurboQuantVe
- filter operator {op!r} not supported by TurboQuantVectorStor
- module {__name__!r} has no attribute {name!r}
- duplicate id in batch: {k!r}
AI-assisted analysis of RyanCodrai/turbovec@ccab9f325e (2026-09-06).
Data as JSON: /api/errors/bff3a80755c93314.
Report an issue: GitHub.