pandas-dev/pandas · error · ValueError

Cannot mask with non-boolean array containing NA / NaN value

Error message

Cannot mask with non-boolean array containing NA / NaN values

What it means

Raised in pandas/core/common.py:151 within the boolean-mask validation used by __getitem__/loc when a mask array of object dtype contains NA/NaN among non-boolean entries. The guard distinguishes a pure boolean mask (ok) from a mask that mixes booleans and NaN, which is ambiguous and cannot safely select rows.

Source

Thrown at pandas/core/common.py:151

    See Also
    --------
    check_array_indexer : Check that `key` is a valid array to index,
        and convert to an ndarray.
    """
    if isinstance(
        key,
        (ABCSeries, np.ndarray, ABCIndex, ABCExtensionArray, ABCNumpyExtensionArray),
    ) and not isinstance(key, ABCMultiIndex):
        if key.dtype == np.object_:
            key_array = np.asarray(key)

            if not lib.is_bool_array(key_array):
                na_msg = "Cannot mask with non-boolean array containing NA / NaN values"
                if lib.is_bool_array(key_array, skipna=True):
                    # Don't raise on e.g. ["A", "B", np.nan], see
                    #  test_loc_getitem_list_of_labels_categoricalindex_with_na
                    raise ValueError(na_msg)
                return False
            return True
        elif is_bool_dtype(key.dtype):
            return True
    elif isinstance(key, list):
        # check if np.array(key).dtype would be bool
        if len(key) > 0:
            if type(key) is not list:
                # GH#42461 cython will raise TypeError if we pass a subclass
                key = list(key)
            return lib.is_bool_list(key)

    return False


def cast_scalar_indexer(val: Any) -> Any:
    """
    Disallow indexing with a float key, even if that key is a round number.

View on GitHub (pinned to 71959b8cb9)

Solutions

  1. Fill the mask's missing values before indexing: `df[mask.fillna(False)]` or `mask.astype('boolean').fillna(False)`.
  2. Use pandas nullable boolean dtype: convert with `.astype('boolean')` which has a native NA, then decide True/False explicitly.
  3. Recompute the mask so NaN compares to False: `df['x'].eq('a', fill_value=False)` or `df['x'].fillna('').eq('a')`.

Example fix

# before
mask = df['x'] == 'a'   # object column -> NaN where x is NaN
df[mask]

# after
df[df['x'].fillna('').eq('a')]
Defensive patterns

Strategy: validation

Validate before calling

import numpy as np

def clean_boolean_mask(mask):
    arr = np.asarray(mask)
    if arr.dtype == object or arr.dtype.kind == 'O':
        return np.array([bool(x) if x is not np.nan else False for x in arr], dtype=bool)
    return arr.astype(bool)

df[clean_boolean_mask(mask)]

Type guard

import numpy as np

def is_clean_bool_mask(mask) -> bool:
    arr = np.asarray(mask)
    return arr.dtype == bool or (arr.dtype == object and not np.isnan(arr).any())

Try / catch

try:
    sub = df[mask]
except ValueError as e:
    if 'Cannot mask with non-boolean' in str(e):
        mask = mask.fillna(False) if hasattr(mask, 'fillna') else mask
        sub = df[mask]
    else:
        raise

Prevention

When it happens

Trigger: `df[mask]` or `df.loc[mask]` where `mask` is an object-dtype array/Series containing values like [True, False, np.nan, True]. Commonly arises from elementwise comparisons on object columns, or a Series of booleans with missing values, or a list with NaN.

Common situations: Comparing object/nullable columns producing NaN (e.g. `df['x'] == 'a'` where x has NaN), boolean masks built via `np.where` without a fillna, or masks derived from joins/groupby that introduce NaN alignment.

Related errors


AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07). Data as JSON: /api/errors/ac7c4422e6ba3d22. Report an issue: GitHub.