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
- Fill NA explicitly: mask = mask.fillna(False) or mask = mask.astype('boolean').fillna(False).
- Use nullable boolean dtype: df['flag'].astype('boolean').
- Drop NA before masking: df = df[df['flag'].notna()]; df = df[mask].
- 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
- Prefer 'boolean' nullable dtype for masks.
- fillna(False) any mask before .loc indexing.
- Avoid object dtype for boolean columns; convert at load time.
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
- multi-dimensional indexing not allowed
- Value must be 1-D array-like or scalar
- abs(axis) must be less than ndim
- can only convert an array of size 1 to a Python scalar
- can only convert an array of size 1 to a Python scalar
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)