{"record":{"id":"6738853640e18b4c","repo":"microsoft/semantic-kernel","slug":"method-node-func-attr-is-not-available-in-filt","errorCode":null,"errorMessage":"Method '{node.func.attr}' is not available in filter expressions.","messagePattern":"Method '(.+?)' is not available in filter expressions\\.","errorType":"exception","errorClass":"VectorStoreOperationException","httpStatus":null,"severity":"error","filePath":"python/semantic_kernel/connectors/in_memory.py","lineNumber":297,"sourceCode":"            try:\n                func = self._direct_call_functions[node.func.id]\n            except KeyError as e:\n                raise VectorStoreOperationException(\n                    f\"Function '{node.func.id}' is only supported as a method call in filter expressions.\"\n                ) from e\n            return func(*args)\n\n        if isinstance(node.func, ast.Attribute):\n            target = self.evaluate(node.func.value, context)\n            if node.func.attr == \"contains\":\n                if len(args) != 1:\n                    raise VectorStoreOperationException(\"Method 'contains' expects exactly one argument.\")\n                return args[0] in target\n\n            try:\n                func = getattr(target, node.func.attr)\n            except AttributeError as e:\n                raise VectorStoreOperationException(\n                    f\"Method '{node.func.attr}' is not available in filter expressions.\"\n                ) from e\n\n            if not callable(func):\n                raise VectorStoreOperationException(\n                    f\"Attribute '{node.func.attr}' is not callable in filter expressions.\"\n                )\n            return func(*args)\n\n        raise VectorStoreOperationException(\n            f\"Call target node type '{type(node.func).__name__}' is not allowed in filter expressions.\"\n        )\n\n    def _compare(self, operator_node: ast.AST, left: Any, right: Any) -> bool:\n        \"\"\"Evaluate a comparison operator.\"\"\"\n        if isinstance(operator_node, ast.Eq):\n            return left == right\n        if isinstance(operator_node, ast.NotEq):","sourceCodeStart":279,"sourceCodeEnd":315,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/python/semantic_kernel/connectors/in_memory.py#L279-L315","documentation":"For method calls (ast.Attribute func) other than contains, _eval_Call resolves the method via getattr(target, node.func.attr). If the target value has no such attribute, AttributeError is caught and re-raised as VectorStoreOperationException. The method name already passed the static allowed_filter_functions check, so this fires when the field's runtime type does not provide that method.","triggerScenarios":"Calling a string method on a non-string field, e.g. lambda x: x.count.startswith('a') where count is an int, or lambda x: x.tags.upper() where tags is a list. The method name is allowed but the value lacks it.","commonSituations":"Field type mismatch between the data model and the actual stored value; optional fields returning None; schema drift; assuming a field is a string when it is a number/list.","solutions":["Ensure the field is the expected type before calling type-specific methods on it.","Coerce explicitly with an allowed builtin: lambda x: str(x.count).startswith('a').","Guard for None: lambda x: x.count is not None and str(x.count).startswith('a')."],"exampleFix":"# before\nVectorSearchOptions(filter=lambda x: x.count.startswith('a'))  # count is int -> [1319]\n\n# after\nVectorSearchOptions(filter=lambda x: str(x.count).startswith('a'))","handlingStrategy":"type-guard","validationCode":"def coerce_before_method_call(filter_str: str, field_types: dict[str, type]) -> str:\n    # ensure string methods are called on str-typed fields, e.g. wrap with str()\n    for field, typ in field_types.items():\n        if typ is not str and any(m in filter_str for m in ('.startswith', '.endswith', '.upper', '.lower', '.strip')):\n            filter_str = filter_str.replace(f'{field}.', f'str({field}).')\n    return filter_str","typeGuard":"def field_supports_method(value, method: str) -> bool:\n    return callable(getattr(value, method, None))","tryCatchPattern":"from semantic_kernel.exceptions import VectorStoreOperationException\ntry:\n    await collection.search(vector=[...], options=opts)\nexcept VectorStoreOperationException as ex:\n    if 'is not available in filter expressions' in str(ex):\n        # coerce the field to the expected type, e.g. str(x.count).startswith('a')\n        opts.filter = \"lambda x: str(x.count).startswith('a')\"\n        await collection.search(vector=[...], options=opts)\n    else:\n        raise","preventionTips":["Confirm a field's type before calling type-specific methods on it.","Coerce with allowed builtins (str/int/float) when the value may be a different type.","Guard optional fields against None before calling methods."],"tags":["in-memory","filter","data-model","type-mismatch"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}