{"record":{"id":"c2813a765889f86c","repo":"microsoft/semantic-kernel","slug":"call-target-node-type-type-node-func-name-c2813a","errorCode":null,"errorMessage":"Call target node type '{type(node.func).__name__}' is not allowed in filter expressions. Only direct function and method calls are supported.","messagePattern":"Call target node type '(.+?)' is not allowed in filter expressions\\. Only direct function and method calls are supported\\.","errorType":"validation","errorClass":"VectorStoreOperationException","httpStatus":null,"severity":"error","filePath":"python/semantic_kernel/connectors/in_memory.py","lineNumber":803,"sourceCode":"                    \"This attribute could be used to escape the filter sandbox.\"\n                )\n\n            # For Name nodes, only allow the lambda parameter\n            if isinstance(node, ast.Name) and node.id not in lambda_param_names:\n                raise VectorStoreOperationException(\n                    f\"Use of name '{node.id}' is not allowed in filter expressions. \"\n                    f\"Only the lambda parameter(s) ({', '.join(lambda_param_names)}) can be used.\"\n                )\n\n            # For Call nodes, validate that only allowed functions are called\n            if isinstance(node, ast.Call):\n                func_name: str\n                if isinstance(node.func, ast.Name):\n                    func_name = node.func.id\n                elif isinstance(node.func, ast.Attribute):\n                    func_name = node.func.attr\n                else:\n                    raise VectorStoreOperationException(\n                        f\"Call target node type '{type(node.func).__name__}' is not allowed in filter expressions. \"\n                        \"Only direct function and method calls are supported.\"\n                    )\n\n                if func_name not in self.allowed_filter_functions:\n                    raise VectorStoreOperationException(\n                        f\"Function '{func_name}' is not allowed in filter expressions. \"\n                        f\"Allowed functions: {', '.join(sorted(self.allowed_filter_functions))}\"\n                    )\n\n            if (\n                isinstance(node, (ast.List, ast.Tuple, ast.Set))\n                and len(node.elts) > self.max_filter_literal_collection_size\n            ):\n                raise VectorStoreOperationException(\n                    \"Collection literals in filter expressions exceed the maximum allowed size.\"\n                )\n","sourceCodeStart":785,"sourceCodeEnd":821,"githubUrl":"https://github.com/microsoft/semantic-kernel/blob/c028a0c7dc4f0814cdcbaba9d998f187a41197bf/python/semantic_kernel/connectors/in_memory.py#L785-L821","documentation":"Thrown by InMemoryCollection._parse_and_validate_filter (in_memory.py:803) when an ast.Call node's target (.func) is neither ast.Name nor ast.Attribute. The sandbox only supports direct function calls (name(...)) and direct method calls (obj.method(...)); indirect calls like calling a subscripted or parenthesized expression are blocked to prevent dynamic dispatch out of the sandbox.","triggerScenarios":"A string filter whose call target is computed, e.g. \"lambda x: (x.get)('a')\", \"lambda x: x['f'](1)\", or \"lambda x: (lambda y: y)(x)\". Anything where node.func is not a Name or Attribute trips in_memory.py:802-806.","commonSituations":"Trying to alias a method then call it; wrapping callables in parentheses; attempting higher-order or lambda-returning expressions inside the filter string; obfuscated input that an attacker hopes will evade the function-name allowlist.","solutions":["Rewrite the call as a direct method call: \"lambda x: x.get('a')\" instead of \"(x.get)('a')\".","Replace indirect dispatch with one of the allowed direct function/method names (len, str, get, contains, etc.).","If the logic cannot be expressed as a direct call, move that logic out of the string filter and pass a Python callable in options.filter.","Audit untrusted filter input: this error often indicates an attempt to bypass the sandbox."],"exampleFix":"# before\nfilter = \"lambda x: (x.get)('status') == 'ok'\"\n\n# after\nfilter = \"lambda x: x.get('status') == 'ok'","handlingStrategy":"validation","validationCode":"import ast\n\ndef uses_only_direct_calls(filter_str: str) -> bool:\n    tree = ast.parse(filter_str, mode=\"eval\")\n    for node in ast.walk(tree):\n        if isinstance(node, ast.Call) and not isinstance(node.func, (ast.Name, ast.Attribute)):\n            return False\n    return True","typeGuard":"def is_direct_call_filter(filter_str: str) -> bool:\n    try:\n        tree = ast.parse(filter_str, mode=\"eval\")\n    except SyntaxError:\n        return False\n    return all(\n        not (isinstance(n, ast.Call) and not isinstance(n.func, (ast.Name, ast.Attribute)))\n        for n in ast.walk(tree)\n    )","tryCatchPattern":"from semantic_kernel.exceptions.vector_store_exceptions import VectorStoreOperationException\n\ntry:\n    opts = VectorSearchOptions(filter=filter_str)\nexcept VectorStoreOperationException as ex:\n    if \"Call target node type\" in str(ex):\n        filter_str = rewrite_to_direct_call(filter_str)","preventionTips":["Write calls as direct name(...) or obj.method(...) only; never parenthesize or subscript the callable before calling.","Do not attempt higher-order functions inside string filters.","Treat an indirect-call attempt in untrusted input as a likely sandbox-escape probe.","Pass a Python callable when the logic needs richer dispatch."],"tags":["in-memory-collection","filter","sandbox","ast","call-dispatch"],"backgroundTag":null,"analyzedSha":"c028a0c7dc4f0814cdcbaba9d998f187a41197bf","analyzedAt":"2026-08-13T13:48:05.040Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}