{"record":{"id":"050accb1a98ab6f7","repo":"pandas-dev/pandas","slug":"name-key-is-not-defined","errorCode":null,"errorMessage":"name '{key}' is not defined","messagePattern":"name '(.+?)' is not defined","errorType":"exception","errorClass":"UndefinedVariableError","httpStatus":null,"severity":"error","filePath":"pandas/core/computation/scope.py","lineNumber":245,"sourceCode":"            if is_local:\n                return self.scope[key]\n\n            # not a local variable so check in resolvers if we have them\n            if self.has_resolvers:\n                return self.resolvers[key]\n\n            # if we're here that means that we have no locals and we also have\n            # no resolvers\n            assert not is_local and not self.has_resolvers\n            return self.scope[key]\n        except KeyError:\n            try:\n                # last ditch effort we look in temporaries\n                # these are created when parsing indexing expressions\n                # e.g., df[df > 0]\n                return self.temps[key]\n            except KeyError as err:\n                raise UndefinedVariableError(key, is_local) from err\n\n    def swapkey(self, old_key: str, new_key: str, new_value=None) -> None:\n        \"\"\"\n        Replace a variable name, with a potentially new value.\n\n        Parameters\n        ----------\n        old_key : str\n            Current variable name to replace\n        new_key : str\n            New variable name to replace `old_key` with\n        new_value : object\n            Value to be replaced along with the possible renaming\n        \"\"\"\n        if self.has_resolvers:\n            maps = self.resolvers.maps + self.scope.maps\n        else:\n            maps = self.scope.maps","sourceCodeStart":227,"sourceCodeEnd":263,"githubUrl":"https://github.com/pandas-dev/pandas/blob/71959b8cb9b2459c16e14b34f28b178ccfe14735/pandas/core/computation/scope.py#L227-L263","documentation":"UndefinedVariableError raised by Scope.resolve() in pandas/core/computation/scope.py:245 with is_local=False/None. It means a bare identifier referenced inside DataFrame.query()/DataFrame.eval()/pd.eval() was not found in any of: the DataFrame columns (resolvers), the calling frame's scope, or the temporaries produced while parsing indexing expressions. The message format 'name {key!r} is not defined' mirrors Python's own NameError phrasing, because UndefinedVariableError subclasses NameError.","triggerScenarios":"df.query('A > x') where 'A' is a column but 'x' is neither a column nor a variable in the calling scope; df.eval('col1 + col2') where 'col2' is misspelled or absent; pd.eval('foo + 1', local_dict={}, global_dict={}) with an emptied namespace (GH 47084); referencing a builtin like sin inside query (query does not pick up builtins: df.query('sin > 5')).","commonSituations":"Renaming a DataFrame column but forgetting to update query/eval strings; dynamic generation of query strings from user input where a column name is missing; passing local_dict/global_dict explicitly to pd.eval and accidentally excluding the needed name; copy-pasted query expressions from a notebook into a function where the referenced local no longer exists; expecting Python builtins (sin, cos, abs) to resolve inside query.","solutions":["Check the identifier against df.columns (e.g. assert 'x' in df.columns) before calling query/eval when the string is dynamic.","If the name should be a Python variable, prefix it with '@' (df.query('A > @x')); if it should be a column, correct the spelling or add the column.","When calling pd.eval with explicit namespaces, ensure the name is present in local_dict or global_dict (do not pass empty dicts unless you intend to hide the namespace).","For dynamic/user-supplied expressions, parse with ast and validate every Name node against an allow-list of columns + known locals before evaluation."],"exampleFix":"// before\ndf.query(\"A > x\")  # UndefinedVariableError: name 'x' is not defined\n\n// after\nx = 5\ndf.query(\"A > @x\")  # reference the local explicitly","handlingStrategy":"validation","validationCode":"import ast\n\ndef validate_query_names(expr: str, df, extra_locals: dict | None = None) -> list[str]:\n    \"\"\"Return list of undefined bare names (excluding @locals and callables).\"\"\"\n    tree = ast.parse(expr, mode='eval')\n    cols = set(df.columns)\n    known = set((extra_locals or {}).keys())\n    problems = []\n    for n in ast.walk(tree):\n        if isinstance(n, ast.Name) and isinstance(n.ctx, ast.Load):\n            if n.id not in cols and n.id not in known:\n                problems.append(n.id)\n    return problems\n\n# usage\nbad = validate_query_names('A > x', df)\nassert not bad, f'undefined names: {bad}'\ndf.query('A > x')","typeGuard":"def names_are_resolvable(expr: str, df, local_ns: dict) -> bool:\n    import ast\n    tree = ast.parse(expr, mode='eval')\n    cols = set(df.columns)\n    for n in ast.walk(tree):\n        if isinstance(n, ast.Name):\n            if n.id not in cols and n.id not in local_ns:\n                return False\n    return True","tryCatchPattern":"import re\nfrom pandas.errors import UndefinedVariableError\n\ntry:\n    result = df.query(expr)\nexcept UndefinedVariableError as e:\n    # NOTE: UndefinedVariableError does not expose .name/.is_local as attributes;\n    # the offending identifier only lives in the message text.\n    m = re.search(r\"name '([^']+)' is not defined$\", str(e))\n    bad = m.group(1) if m else str(e)\n    raise ValueError(f'query references unknown column/variable {bad!r}; columns={list(df.columns)}') from e","preventionTips":["Treat query/eval strings as code: lint their identifiers against df.columns before running.","Generate query strings from an allow-list of column names rather than string-interpolating user input.","When using pd.eval with explicit namespaces, double-check local_dict/global_dict contain every referenced name.","Remember query does not resolve Python builtins; prefix locals with '@'."],"tags":["query","eval","name-resolution","undefined-variable"],"analyzedSha":"71959b8cb9b2459c16e14b34f28b178ccfe14735","analyzedAt":"2026-08-07T01:30:20.476Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}