pandas-dev/pandas · error · ValueError

Cannot convert float NaN to integer

Error message

Cannot convert float NaN to integer

What it means

Raised in `Categorical.astype` when the target dtype is an integer kind (`'i'`/`'u'`) but the categorical contains missing values (NaN, coded internally as `-1`). NumPy integer arrays cannot represent NaN, so conversion is refused rather than silently producing garbage values.

Solutions

  1. Drop or fill missing values first: `cat.dropna().astype('int64')` or `cat.fillna(0).astype('int64')`.
  2. Convert to a nullable integer dtype: `cat.astype('Int64')` (pandas nullable extension type).
  3. Cast to float instead if NaN must be preserved: `cat.astype('float64')`.
  4. Map codes directly if you want raw integer codes: `cat.codes` (already an int8/16/32 with -1 for NaN).

Example fix

# before
cat = pd.Categorical([1, 2, None])
arr = cat.astype('int64')  # ValueError

# after (nullable)
arr = cat.astype('Int64')
# after (drop NaN)
arr = cat.dropna().astype('int64')
Defensive patterns

Strategy: validation

Validate before calling

def to_int_safe(cat):
    if cat.isna().any():
        raise ValueError('Categorical has NaN; use .astype("Int64") or fillna first')
    return cat.astype('int64')

Type guard

def has_no_missing(cat) -> bool:
    return not cat.isna().any()

Try / catch

try:
    arr = cat.astype('int64')
except ValueError as e:
    if 'Cannot convert float NaN' in str(e):
        arr = cat.astype('Int64')  # nullable
    else:
        raise

Prevention

When it happens

Trigger: `cat.astype('int64')` (or `int32`, `uint16`, etc.) on a Categorical that has any `NaN`/missing entry, or `pd.Categorical([1.0, None]).astype(int)`.

Common situations: Cleaning columns where missing integers were stored as categoricals; converting survey codes back to ints without handling non-responses; pandas ↔ nullable-extension interop where users assume `astype('int')` will just work.

Related errors


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

Appendix: source

Thrown at pandas/core/arrays/categorical.py:623

            # GH 10696/18593/18630
            dtype = self.dtype.update_dtype(dtype)
            self = self.copy() if copy else self
            result = self._set_dtype(dtype, copy=False)
            wrong = result.isna() & ~self.isna()
            if wrong.any():
                warnings.warn(
                    "Constructing a Categorical with a dtype and values containing "
                    "non-null entries not in that dtype's categories is deprecated "
                    "and will raise in a future version.",
                    Pandas4Warning,
                    stacklevel=find_stack_level(),
                )

        elif isinstance(dtype, ExtensionDtype):
            return super().astype(dtype, copy=copy)

        elif dtype.kind in "iu" and self.isna().any():
            raise ValueError("Cannot convert float NaN to integer")

        elif len(self.codes) == 0 or len(self.categories) == 0:
            # For NumPy 1.x compatibility we cannot use copy=None.  And
            # `copy=False` has the meaning of `copy=None` here:
            if not copy:
                result = np.asarray(self, dtype=dtype)
            else:
                result = np.array(self, dtype=dtype)

        else:
            # GH8628 (PERF): astype category codes instead of astyping array
            new_cats = self.categories._values

            try:
                new_cats = new_cats.astype(dtype=dtype, copy=copy)
                fill_value = self.categories._na_value
                if not is_valid_na_for_dtype(fill_value, dtype):
                    fill_value = lib.item_from_zerodim(

View on GitHub (pinned to 3b7651241d)