{"record":{"id":"afeb610c372249b6","repo":"pandas-dev/pandas","slug":"invalid-function-call-node-func-id","errorCode":null,"errorMessage":"Invalid function call {node.func.id}","messagePattern":"Invalid function call (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"pandas/core/computation/expr.py","lineNumber":685,"sourceCode":"    def visit_Call(self, node, side=None, **kwargs):\n        if isinstance(node.func, ast.Attribute) and node.func.attr != \"__call__\":\n            res = self.visit_Attribute(node.func)\n        elif not isinstance(node.func, ast.Name):\n            raise TypeError(\"Only named functions are supported\")\n        else:\n            try:\n                res = self.visit(node.func)\n            except UndefinedVariableError:\n                # Check if this is a supported function name\n                try:\n                    res = FuncNode(node.func.id)\n                except ValueError:\n                    # Raise original error\n                    raise\n\n        if res is None:\n            # error: \"expr\" has no attribute \"id\"\n            raise ValueError(\n                f\"Invalid function call {node.func.id}\"  # type: ignore[union-attr]\n            )\n        if hasattr(res, \"value\"):\n            res = res.value\n\n        if isinstance(res, FuncNode):\n            new_args = [self.visit(arg) for arg in node.args]\n\n            if node.keywords:\n                raise TypeError(\n                    f'Function \"{res.name}\" does not support keyword arguments'\n                )\n\n            return res(*new_args)\n\n        else:\n            new_args = [self.visit(arg)(self.env) for arg in node.args]\n","sourceCodeStart":667,"sourceCodeEnd":703,"githubUrl":"https://github.com/pandas-dev/pandas/blob/3b7651241d4da534b3559b60ef128e1c34f54116/pandas/core/computation/expr.py#L667-L703","documentation":"Raised by pandas.eval()/DataFrame.query() when a function call inside the expression string cannot be resolved. The visitor first tries to resolve the name in the user's scope (locals/globals), and on UndefinedVariableError falls back to constructing a FuncNode from the supported MATHOPS list (sin, cos, exp, log, sqrt, abs, ...). If both lookups fail the original undefined-variable error is re-raised; this ValueError fires only when the resolved result is None, meaning the call target is neither a scope variable nor a supported numpy math function.","triggerScenarios":"Calling df.query('foo(A)') or pd.eval('foo(A)') where 'foo' is not defined in the local/global namespace and is not one of the whitelisted numpy math functions. Also triggered by chained attribute calls where visit_Attribute returns None, or by referencing a function name that shadows a math op but resolves to a non-callable.","commonSituations":"Typos in function names inside query strings (e.g. 'sine(A)' instead of 'sin(A)'). Attempting to call arbitrary Python/NumPy functions (np.where, len, round, custom ufuncs) inside eval/query, which the engine does not support. Forgetting to prefix a user function with @ (only @-prefixed locals are visible, and even then only callables resolving through the scope path work).","solutions":["Replace the unsupported function with one of the whitelisted numpy math functions: sin, cos, tan, exp, log, expm1, log1p, sqrt, sinh, cosh, tanh, arcsin, arccos, arctan, arccosh, arcsinh, arctanh, abs, log10, floor, ceil, arctan2.","If you need a non-whitelisted function, compute it in Python first and pass the result as a @-prefixed local variable: pre = np.where(A>0, A, 0); df.query('@pre > 1').","Drop eval/query entirely and use vectorized boolean indexing: df[df['A'].apply(my_func)].","Check for typos: compare the function name against the MATHOPS tuple in pandas/core/computation/ops.py."],"exampleFix":"// before\ndf.query(\"sine(A) > 0.5\")\ndf.query(\"round(A) > 0\")\n\n// after\ndf.query(\"sin(A) > 0.5\")\nrounded = np.round(df['A'])\ndf[rounded > 0]","handlingStrategy":"validation","validationCode":"import pandas.core.computation.ops as _ops\nSUPPORTED = set(_ops.MATHOPS)\n\ndef is_supported_query_fn(name: str) -> bool:\n    return name in SUPPORTED or name in globals() or name in locals()\n\n# before building the query string\nfn = 'sine'\nassert is_supported_query_fn(fn), f'{fn} is not a supported eval/query function'","typeGuard":"from typing import Any\nimport pandas.core.computation.ops as _ops\n\ndef is_mathop_call(node: Any) -> bool:\n    return isinstance(node.func, type(node)) and getattr(node.func, 'id', None) in _ops.MATHOPS","tryCatchPattern":"try:\n    df.query('foo(A)')\nexcept (ValueError, UndefinedVariableError) as e:\n    # fall back to vectorized Python\n    df[df['A'].apply(foo)]","preventionTips":["Maintain a constant set of whitelisted math functions and assert query strings only reference those or @-locals.","Build query strings from a small templating layer that rejects unknown function tokens.","Run query strings through a dry-run parse on a tiny DataFrame during development."],"tags":["pandas","eval","query","function-call","expression"],"backgroundTag":null,"analyzedSha":"3b7651241d4da534b3559b60ef128e1c34f54116","analyzedAt":"2026-08-11T22:10:44.015Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}