pandas-dev/pandas · error · ValueError

cannot convert NA to integer

Error message

cannot convert NA to integer

What it means

Raised by BaseMaskedArray._astype when casting a masked array containing missing values to an integer numpy dtype. NumPy integer arrays cannot represent NaN/NA, so pandas raises instead of silently producing garbage. This is the friendly upstream message; to_numpy would raise later with a worse one.

Source

Thrown at pandas/core/arrays/masked.py:805

        if isinstance(dtype, ExtensionDtype):
            eacls = dtype.construct_array_type()
            return eacls._from_sequence(self, dtype=dtype, copy=copy)

        na_value: float | np.datetime64 | lib.NoDefault

        # coerce
        if dtype.kind == "f":
            # In astype, we consider dtype=float to also mean na_value=np.nan
            na_value = np.nan
        elif dtype.kind == "M":
            unit = np.datetime_data(dtype)[0]
            na_value = np.datetime64("NaT", unit)  # type: ignore[call-overload]
        else:
            na_value = lib.no_default

        # to_numpy will also raise, but we get somewhat nicer exception messages here
        if dtype.kind in "iu" and self._hasna:
            raise ValueError("cannot convert NA to integer")
        if dtype.kind == "b" and self._hasna:
            # careful: astype_nansafe converts np.nan to True
            raise ValueError("cannot convert float NaN to bool")

        data = self.to_numpy(dtype=dtype, na_value=na_value, copy=copy)
        return data

    __array_priority__ = 1000  # higher than ndarray so ops dispatch to us

    def __array__(
        self, dtype: NpDtype | None = None, copy: bool | None = None
    ) -> np.ndarray:
        """
        the array interface, return my values
        We return an object array here to preserve our scalar values
        """
        if copy is False:
            if not self._hasna:

View on GitHub (pinned to 71959b8cb9)

Solutions

  1. Fill or drop missing values before casting: arr.fillna(0).astype('int64') or df.dropna(subset=['col']).astype({'col':'int64'}).
  2. Cast to a nullable integer dtype instead: arr.astype('Int64').
  3. Cast to float64 if NaN must be preserved: arr.astype('float64').
  4. Pass an na_value if going through to_numpy directly.

Example fix

// before
s.astype("int64")  # raises: cannot convert NA to integer

// after
s.fillna(0).astype("int64")
Defensive patterns

Strategy: validation

Validate before calling

def safe_int_cast(arr):
    if getattr(arr, "_hasna", False):
        raise ValueError("array has NA; fill or drop before casting to integer")
    return arr.astype("int64")

Type guard

def is_na_free(arr) -> bool:
    return not getattr(arr, "_hasna", False)

Try / catch

try:
    out = arr.astype("int64")
except ValueError as e:
    if "cannot convert NA to integer" in str(e):
        out = arr.fillna(0).astype("int64")
    else:
        raise

Prevention

When it happens

Trigger: Calling arr.astype('int64'), arr.astype(np.int32), or Series.astype('Int64' -> 'int64') on a masked array whose self._hasna is True. Equivalent path through np.asarray with an int dtype.

Common situations: Reading dirty CSV/data where NaNs appear in a numeric column typed as integer; converting a nullable Int64 column to plain numpy int64 for a library that does not accept NaN; chaining dropna incorrectly.

Related errors


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