pandas-dev/pandas · error · ValueError

Invalid function call

Error message

Invalid function call {node.func.id}

What it means

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.

Solutions

  1. 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.
  2. 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').
  3. Drop eval/query entirely and use vectorized boolean indexing: df[df['A'].apply(my_func)].
  4. Check for typos: compare the function name against the MATHOPS tuple in pandas/core/computation/ops.py.

Example fix

// before
df.query("sine(A) > 0.5")
df.query("round(A) > 0")

// after
df.query("sin(A) > 0.5")
rounded = np.round(df['A'])
df[rounded > 0]
Defensive patterns

Strategy: validation

Validate before calling

import pandas.core.computation.ops as _ops
SUPPORTED = set(_ops.MATHOPS)

def is_supported_query_fn(name: str) -> bool:
    return name in SUPPORTED or name in globals() or name in locals()

# before building the query string
fn = 'sine'
assert is_supported_query_fn(fn), f'{fn} is not a supported eval/query function'

Type guard

from typing import Any
import pandas.core.computation.ops as _ops

def is_mathop_call(node: Any) -> bool:
    return isinstance(node.func, type(node)) and getattr(node.func, 'id', None) in _ops.MATHOPS

Try / catch

try:
    df.query('foo(A)')
except (ValueError, UndefinedVariableError) as e:
    # fall back to vectorized Python
    df[df['A'].apply(foo)]

Prevention

When it happens

Trigger: 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.

Common situations: 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).

Related errors


AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11). Data as JSON: /api/errors/afeb610c372249b6. Report an issue: GitHub.

Appendix: source

Thrown at pandas/core/computation/expr.py:685

    def visit_Call(self, node, side=None, **kwargs):
        if isinstance(node.func, ast.Attribute) and node.func.attr != "__call__":
            res = self.visit_Attribute(node.func)
        elif not isinstance(node.func, ast.Name):
            raise TypeError("Only named functions are supported")
        else:
            try:
                res = self.visit(node.func)
            except UndefinedVariableError:
                # Check if this is a supported function name
                try:
                    res = FuncNode(node.func.id)
                except ValueError:
                    # Raise original error
                    raise

        if res is None:
            # error: "expr" has no attribute "id"
            raise ValueError(
                f"Invalid function call {node.func.id}"  # type: ignore[union-attr]
            )
        if hasattr(res, "value"):
            res = res.value

        if isinstance(res, FuncNode):
            new_args = [self.visit(arg) for arg in node.args]

            if node.keywords:
                raise TypeError(
                    f'Function "{res.name}" does not support keyword arguments'
                )

            return res(*new_args)

        else:
            new_args = [self.visit(arg)(self.env) for arg in node.args]

View on GitHub (pinned to 3b7651241d)