pandas-dev/pandas · error · ValueError

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

Error message

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

What it means

Raised by is_bool_indexer when the key is an object-dtype array (or Series/Index/EA) that lib.is_bool_array reports as bool-with-skipna but not strict bool — i.e. it contains True/False plus NA/NaN. Object arrays of pure non-bool values (e.g. strings) are rejected by returning False (caller treats as label list), but a bool array containing NaN is ambiguous between mask and label semantics, so pandas raises ValueError. The guard exists because boolean masks with NaN cause silent row-dropping in the past.

Solutions

  1. Fill NA explicitly: mask = mask.fillna(False) or mask = mask.astype('boolean').fillna(False).
  2. Use nullable boolean dtype: df['flag'].astype('boolean').
  3. Drop NA before masking: df = df[df['flag'].notna()]; df = df[mask].
  4. Rebuild the mask with a strict comparison that cannot produce NaN.

Example fix

// before
mask = pd.Series([True, False, None])
out = df.loc[mask]
// after
mask = pd.Series([True, False, None]).astype('boolean').fillna(False)
out = df.loc[mask]
Defensive patterns

Strategy: validation

Validate before calling

mask = pd.Series(mask_array)
if mask.dtype == object:
    mask = mask.astype('boolean').fillna(False)
out = df.loc[mask]

Type guard

def is_clean_bool_mask(mask) -> bool:
    import numpy as np
    s = pd.Series(mask) if not isinstance(mask, pd.Series) else mask
    if s.dtype == object:
        s = s.astype('boolean')
    return s.notna().all() and pd.api.types.is_bool_dtype(s)

Prevention

When it happens

Trigger: df.loc[pd.Series([True, False, np.nan])]; df[df['flag'].where(df['flag'].notna())]; a column with dtype object holding bools and None; masking after an operation that introduced NaN (e.g. .where(cond) with no fill).

Common situations: Reading Excel/CSV where a boolean column became object dtype with blanks; chained comparisons that yield NaN; user-built masks mixing bool and None; nullable pyarrow-backed bool arrays that landed in object dtype.

Related errors


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

Appendix: 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 3b7651241d)