pandas-dev/pandas · error · ValueError
Cannot convert float NaN to integer
Error message
Cannot convert float NaN to integer
What it means
Raised by Categorical.astype when casting to an integer dtype ('i' or 'u' kind) while the categorical contains missing values (NaN, coded internally as -1). Integers cannot represent NaN, so pandas refuses rather than silently coercing to a sentinel.
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 71959b8cb9)
Solutions
- Fill missing values first: `cat.fillna(...).astype('int')` or use a sentinel category.
- Cast to pandas' nullable integer: `cat.astype('Int64')` (Int64 accepts pd.NA).
- Drop NaN rows: `cat.dropna().astype('int')` if appropriate.
- Operate on codes directly via `cat.codes` (already int, with -1 for missing).
Example fix
# before
cat = pd.Categorical(['a', None, 'b'])
cat.astype(int)
# after
cat = pd.Categorical(['a', None, 'b'])
cat.astype('Int64') # nullable integer, then map if needed Defensive patterns
Strategy: validation
Validate before calling
def cat_to_int(cat):
if cat.isna().any():
return cat.astype('Int64') # nullable int
return cat.astype('int64') Type guard
def has_no_na(cat) -> bool:
return not bool(cat.isna().any()) Try / catch
try:
out = cat.astype('int')
except ValueError as e:
if 'NaN to integer' in str(e):
out = cat.astype('Int64')
else:
raise Prevention
- Use nullable 'Int64' when missing values are possible.
- Drop or fill NA before astype to plain int.
- Use cat.codes (int, -1 for NA) when you want positions.
When it happens
Trigger: `cat.astype('int')`, `cat.astype(np.int64)`, or `cat.astype('Int64')`-via-int path when `cat.isna().any()` is True. Commonly hit when a categorical came from data with missing entries.
Common situations: Reading survey/enum data with blanks, then converting codes to int for modeling; or downstream code assuming no missing values.
Related errors
- Cannot cast {self.categories.dtype} dtype to {dtype}
- Value must be a nonnegative integer or None
- Lengths must match.
- The categories must be provided in 'categories' or 'dtype'.
- new categories need to have the same number of items as the
AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07).
Data as JSON: /api/errors/2958cb277e2ce7d2.
Report an issue: GitHub.