{"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/71959b8cb9b2459c16e14b34f28b178ccfe14735/pandas/core/computation/expr.py#L667-L703","documentation":"In visit_Call, after attempting to resolve node.func (via visit or FuncNode lookup), if the result res is None the function name resolved to nothing callable and pandas raises ValueError naming node.func.id. This typically means a name in the expression resolved to None in scope, or a FuncNode lookup path returned None.","triggerScenarios":"df.eval('foo(a)') where 'foo' is a name in scope whose value is None, or a callable name that fails resolution and yields None through a custom resolver.","commonSituations":"Variable shadowing where a column or local named like the intended function holds None. Resolvers that return None for unknown names instead of raising UndefinedVariableError.","solutions":["Verify the function name is spelled correctly and is actually callable in scope.","Rename the colliding variable/column so the function name resolves to the callable.","Register the function in local_dict/global_dict explicitly."],"exampleFix":"// before\nfoo = None\ndf.eval('foo(a)')\n// after\nimport math as foo_math\npd.eval('foo_math.sqrt(a)', local_dict={'foo_math': foo_math})","handlingStrategy":"validation","validationCode":"def validate_callable_in_scope(name: str, local_dict, global_dict) -> None:\n    obj = (local_dict or {}).get(name, (global_dict or {}).get(name))\n    if obj is None:\n        raise ValueError(f'{name!r} resolves to None; cannot be called in eval')\n\n# before evaluating 'foo(a)':\nvalidate_callable_in_scope('foo', local_dict, global_dict)","typeGuard":"def name_resolves_to_callable(name: str, local_dict, global_dict) -> bool:\n    obj = (local_dict or {}).get(name, (global_dict or {}).get(name))\n    return callable(obj)","tryCatchPattern":"try:\n    df.eval(expr)\nexcept ValueError as e:\n    if 'Invalid function call' in str(e):\n        # ensure the function is registered before retrying\n        pd.eval(expr, local_dict={**locals()})\n    raise","preventionTips":["Do not shadow callable names with None-valued columns or locals.","Register custom functions in local_dict explicitly when calling them from eval.","Spell function names exactly; check for typos."],"tags":["pandas","eval","functions","name-resolution"],"analyzedSha":"71959b8cb9b2459c16e14b34f28b178ccfe14735","analyzedAt":"2026-08-07T01:30:20.476Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}