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
- Drop or fill missing values first: `cat.dropna().astype('int64')` or `cat.fillna(0).astype('int64')`.
- Convert to a nullable integer dtype: `cat.astype('Int64')` (pandas nullable extension type).
- Cast to float instead if NaN must be preserved: `cat.astype('float64')`.
- 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
- Use the nullable `Int64`/`Int32` dtypes when missing values must survive a cast.
- Drop or impute missing entries before casting to a numpy integer dtype.
- Inspect `cat.isna().any()` before any integer cast.
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
- Cannot cast dtype to
- cannot convert NA to integer
- codes cannot contain NA values
- codes need to be array-like integers
- codes need to be between -1 and len(categories)-1
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)