{"record":{"id":"534c3a057f3722f3","repo":"pandas-dev/pandas","slug":"cannot-evaluate-scalar-only-bool-ops","errorCode":null,"errorMessage":"cannot evaluate scalar only bool ops","messagePattern":"cannot evaluate scalar only bool ops","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"pandas/core/computation/ops.py","lineNumber":487,"sourceCode":"        rhs = self.rhs\n        lhs = self.lhs\n\n        # GH#24883 unwrap dtype if necessary to ensure we have a type object\n        rhs_rt = rhs.return_type\n        rhs_rt = getattr(rhs_rt, \"type\", rhs_rt)\n        lhs_rt = lhs.return_type\n        lhs_rt = getattr(lhs_rt, \"type\", lhs_rt)\n        if (\n            (lhs.is_scalar or rhs.is_scalar)\n            and self.op in _bool_ops_dict\n            and (\n                not (\n                    issubclass(rhs_rt, (bool, np.bool_))\n                    and issubclass(lhs_rt, (bool, np.bool_))\n                )\n            )\n        ):\n            raise NotImplementedError(\"cannot evaluate scalar only bool ops\")\n\n\nUNARY_OPS_SYMS = (\"+\", \"-\", \"~\", \"not\")\n_unary_ops_funcs = (operator.pos, operator.neg, operator.invert, operator.invert)\n_unary_ops_dict = dict(zip(UNARY_OPS_SYMS, _unary_ops_funcs, strict=True))\n\n\nclass UnaryOp(Op):\n    \"\"\"\n    Hold a unary operator and its operands.\n\n    Parameters\n    ----------\n    op : str\n        The token used to represent the operator.\n    operand : Term or Op\n        The Term or Op operand to the operator.\n","sourceCodeStart":469,"sourceCodeEnd":505,"githubUrl":"https://github.com/pandas-dev/pandas/blob/3b7651241d4da534b3559b60ef128e1c34f54116/pandas/core/computation/ops.py#L469-L505","documentation":"Raised in BinOp._disallow_scalar_only_bool_ops when at least one operand is scalar, the operator is a boolean op (&, |, and, or), and the operand types are not both bool/np.bool_. The eval engine refuses to silently coerce scalar non-bool values through Python truthiness inside a vectorized boolean expression, because the result would be ambiguous (element-wise vs scalar truth).","triggerScenarios":"pd.eval('1 & 2'), pd.eval('5 and 3'), df.query('A & 1') where one side is a scalar int. Any boolean operator applied between a scalar non-bool (int, float, str) and another term inside eval/query.","commonSituations":"Treating eval like Python and expecting short-circuit truthiness on scalars. Mixing bitwise & with integer masks inside query. Migrating from plain Python boolean expressions to df.query() without converting flags to bool.","solutions":["Convert scalar operands to bool explicitly before the eval: pd.eval('bool(1) & bool(2)') is still rejected — instead pass booleans: flag = True; df.query('@flag & (A > 0)').","Use comparison operators to produce boolean scalars: df.query('(A > 0) & (B > 0)') instead of df.query('A & 1').","Move scalar boolean logic out of the query string and combine in Python afterward.","If the scalar is meant as a mask, broadcast it: pd.eval('(A > 0) & True') works because True is bool."],"exampleFix":"// before\npd.eval(\"1 & 2\")\ndf.query(\"A & 1\")\n\n// after\npd.eval(\"True & False\")\ndf.query(\"A & (B > 0)\")","handlingStrategy":"validation","validationCode":"from pandas.core.computation.ops import _bool_ops_dict\nfrom pandas.core.dtypes.common import is_scalar, is_bool_dtype\nimport numpy as np\n\ndef bool_op_safe(lhs, rhs, op: str) -> bool:\n    if op not in _bool_ops_dict:\n        return True\n    if not (is_scalar(lhs) or is_scalar(rhs)):\n        return True\n    lt = type(lhs); rt = type(rhs)\n    return issubclass(lt, (bool, np.bool_)) and issubclass(rt, (bool, np.bool_))\n\nassert bool_op_safe(1, 2, '&') is False  # would raise","typeGuard":"import numpy as np\nfrom typing import Any\n\ndef operands_bool_safe(lhs: Any, rhs: Any, op: str) -> bool:\n    if op not in ('&', '|', 'and', 'or'):\n        return True\n    return isinstance(lhs, (bool, np.bool_)) and isinstance(rhs, (bool, np.bool_))","tryCatchPattern":"try:\n    pd.eval('1 & 2')\nexcept NotImplementedError as e:\n    if 'scalar only bool ops' in str(e):\n        pd.eval('True & False')\n    else:\n        raise","preventionTips":["Convert scalar operands to bool before boolean ops in eval.","Use comparison operators to produce boolean scalars.","Avoid scalar integer operands with & / | / and / or inside eval strings."],"tags":["pandas","eval","query","boolean","scalar","type-coercion"],"backgroundTag":null,"analyzedSha":"3b7651241d4da534b3559b60ef128e1c34f54116","analyzedAt":"2026-08-11T22:10:44.015Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}