{"record":{"id":"e9b81aed2542519d","repo":"RyanCodrai/turbovec","slug":"both-metadata-value-and-filter-value-must-be-strin-e9b81a","errorCode":null,"errorMessage":"Both metadata value and filter value must be strings for the TEXT_MATCH_INSENSITIVE operator","messagePattern":"Both metadata value and filter value must be strings for the TEXT_MATCH_INSENSITIVE operator","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"turbovec-python/python/turbovec/llama_index.py","lineNumber":771,"sourceCode":"        if op == FilterOperator.CONTAINS:\n            return target in value\n        if op == FilterOperator.TEXT_MATCH:\n            # Case-SENSITIVE substring. `FilterOperator` defines\n            # TEXT_MATCH and TEXT_MATCH_INSENSITIVE as distinct operators,\n            # so folding case here would collapse that distinction and\n            # leave no way to ask for a case-sensitive match. The type\n            # guard is ours: the reference raises AttributeError on a\n            # non-string (issue #302).\n            if isinstance(target, str) and isinstance(value, str):\n                return target in value\n            raise TypeError(\n                \"Both metadata value and filter value must be strings \"\n                \"for the TEXT_MATCH operator\"\n            )\n        if _TEXT_MATCH_INSENSITIVE is not None and op == _TEXT_MATCH_INSENSITIVE:\n            if isinstance(target, str) and isinstance(value, str):\n                return target.lower() in value.lower()\n            raise TypeError(\n                \"Both metadata value and filter value must be strings \"\n                \"for the TEXT_MATCH_INSENSITIVE operator\"\n            )\n        if op == FilterOperator.ALL:\n            # Reference (`utils.py:152-153`): every element of `target`\n            # must be present in the metadata value (which is typically\n            # a list — tag-set matching).\n            return all(t in value for t in target)\n        if op == FilterOperator.ANY:\n            return any(t in value for t in target)\n        raise NotImplementedError(\n            f\"filter operator {op!r} not supported by TurboQuantVectorStore\"\n        )\n\n    def query(self, query: VectorStoreQuery, **_: Any) -> VectorStoreQueryResult:\n        # MMR / SVM / LINEAR_REGRESSION / HYBRID etc. all need access to\n        # full-precision vectors (for pairwise diversity, learned scoring,\n        # or sparse-dense fusion). turbovec discards full precision after","sourceCodeStart":753,"sourceCodeEnd":789,"githubUrl":"https://github.com/RyanCodrai/turbovec/blob/ccab9f325e6ce2a270a87daf01ae4e443bcf2d49/turbovec-python/python/turbovec/llama_index.py#L753-L789","documentation":"TypeError raised in _single_filter_match when a TEXT_MATCH_INSENSITIVE filter encounters a non-string — either the node's metadata value or the filter's comparison value. Substring matching (case-insensitive) is only defined for strings, and the reference impl's AttributeError on non-strings is replaced with this explicit type guard; both operands must be str for the match to proceed.","triggerScenarios":"Querying with FilterOperator.TEXT_MATCH_INSENSITIVE where the metadata value or filter value is an int, float, bool, or list.","commonSituations":"Case-insensitive search over numeric or boolean metadata fields; untyped filter values from user input.","solutions":["Store the metadata field as a string and pass a string filter value","Normalize the value with str() on both ingestion and query sides","Use EQ/IN operators for non-string fields"],"exampleFix":"// before\nMetadataFilter(key=\"year\", value=2024, operator=FilterOperator.TEXT_MATCH_INSENSITIVE)\n// after\nMetadataFilter(key=\"year\", value=\"2024\", operator=FilterOperator.TEXT_MATCH_INSENSITIVE)","handlingStrategy":"type-guard","validationCode":"if op == FilterOperator.TEXT_MATCH_INSENSITIVE and not (isinstance(meta_val, str) and isinstance(filt_val, str)):\n    raise TypeError(\"TEXT_MATCH_INSENSITIVE requires string values\")","typeGuard":null,"tryCatchPattern":"try:\n    store.query(q)\nexcept TypeError as e:\n    if \"TEXT_MATCH_INSENSITIVE\" in str(e):\n        coerce_filter_values_to_str(q.filters)\n        store.query(q)\n    else:\n        raise","preventionTips":["Cast user-supplied filter values to str before querying","Keep case-insensitive searches on string-only metadata fields","Add a filter-builder wrapper that normalizes value types"],"tags":["python","filters","type-mismatch"],"backgroundTag":"type-mismatch","analyzedSha":"ccab9f325e6ce2a270a87daf01ae4e443bcf2d49","analyzedAt":"2026-09-06T08:39:18.516Z","contentChangedAt":"2026-09-06T08:39:18.516Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}