{"record":{"id":"d38723ec1028d59e","repo":"microsoft/semantic-kernel","slug":"function-node-func-id-is-only-supported-as-a-m","errorCode":null,"errorMessage":"Function '{node.func.id}' is only supported as a method call in filter expressions.","messagePattern":"Function '(.+?)' is only supported as a method call in filter expressions\\.","errorType":"exception","errorClass":"VectorStoreOperationException","httpStatus":null,"severity":"error","filePath":"python/semantic_kernel/connectors/in_memory.py","lineNumber":282,"sourceCode":"            return self._safe_numeric_operation(node.op, left, right, lambda a, b: a / b)\n        if isinstance(node.op, ast.Mod):\n            return self._safe_numeric_operation(node.op, left, right, lambda a, b: a % b)\n        if isinstance(node.op, ast.FloorDiv):\n            return self._safe_numeric_operation(node.op, left, right, lambda a, b: a // b)\n\n        raise VectorStoreOperationException(\n            f\"Binary operator '{type(node.op).__name__}' is not allowed in filter expressions.\"\n        )\n\n    def _eval_Call(self, node: ast.Call, context: Mapping[str, Any]) -> Any:\n        \"\"\"Evaluate a function or method call.\"\"\"\n        args = [self.evaluate(arg, context) for arg in node.args]\n\n        if isinstance(node.func, ast.Name):\n            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","sourceCodeStart":264,"sourceCodeEnd":300,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/python/semantic_kernel/connectors/in_memory.py#L264-L300","documentation":"_eval_Call handles bare-name calls (ast.Name func) by looking the name up in _direct_call_functions, which contains only the builtin-style functions callable without a target: len, str, int, float, bool, abs, min, max, sum, any, all. The broader allowed_filter_functions set also includes method names (lower, upper, strip, startswith, endswith, contains, get, keys, values, items) that pass the static check but are NOT direct-callable; calling any of those as a bare name raises VectorStoreOperationException.","triggerScenarios":"A filter that calls a method name as a free function, e.g. lambda x: startswith(x.title, 'a') or lambda x: contains(x.tags, 'a'). These pass static validation (the name is in allowed_filter_functions) but fail at evaluation because they are not in direct_filter_functions.","commonSituations":"Writing method semantics as functions; porting filter syntax from another style; misunderstanding which names are direct-callable.","solutions":["Call methods as methods on the value: lambda x: x.title.startswith('a').","For membership, use the contains special-case (x.tags.contains('a')) or the 'in' operator ('a' in x.tags).","Only use len/str/int/float/bool/abs/min/max/sum/any/all as bare function calls."],"exampleFix":"# before\nVectorSearchOptions(filter=lambda x: startswith(x.title, 'a'))  # -> [1317]\n\n# after\nVectorSearchOptions(filter=lambda x: x.title.startswith('a'))","handlingStrategy":"validation","validationCode":"import ast\nDIRECT = {'len','str','int','float','bool','abs','min','max','sum','any','all'}\ndef bare_calls_are_direct(filter_str: str) -> None:\n    for node in ast.walk(ast.parse(filter_str, mode='eval')):\n        if isinstance(node, ast.Call) and isinstance(node.func, ast.Name):\n            if node.func.id not in DIRECT:\n                raise ValueError(f\"'{node.func.id}' must be called as a method, e.g. x.value.{node.func.id}(...)\")","typeGuard":null,"tryCatchPattern":"from semantic_kernel.exceptions import VectorStoreOperationException\ntry:\n    await collection.search(vector=[...], options=opts)\nexcept VectorStoreOperationException as ex:\n    if 'only supported as a method call' in str(ex):\n        # rewrite startswith(x.f, 'a') -> x.f.startswith('a')\n        ...\n    raise","preventionTips":["Call string/collection methods on the value: x.title.startswith('a').","Use only len/str/int/float/bool/abs/min/max/sum/any/all as bare function calls."],"tags":["in-memory","filter","ast"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}