## TL;DR
Plain `int` dtype cannot represent NaN, so `astype(int)` on a column with missing values raises. Fix it with the nullable integer dtype: `df['c'].astype('Int64')` (capital I), which holds real integers plus pandas NA. It happens because numpy int64 has no NaN slot, while float64 does.

```text
ValueError: cannot convert float NaN to integer
```

## Use this when
- `df['c'].astype(int)` raises on a column with NaN
- Converting a float column with missing values to integer fails
- `int(x)` on a NaN value inside apply/loop code

## Not for
- General astype conversions that work fine
- SQL NULL to integer handling
- Float rounding/precision questions

## Steps

1. Confirm NaN is the cause:

```python
df['c'].isna().sum()
```
Expected output: a count greater than 0.

2. Use the nullable integer dtype (capital I):

```python
df['c'] = df['c'].astype('Int64')
```
Expected output: dtype Int64, integers intact, NaN shown as NA.

3. If you need plain numpy int64 downstream, fill first:

```python
df['c'] = df['c'].fillna(0).astype('int64')
```
Expected output: no NaN left, plain int64 dtype. Pick the fill value deliberately, 0 vs -1 vs drop matters.

4. Same fix inside apply-style code:

```python
df['c'] = df['c'].apply(lambda x: 0 if pd.isna(x) else int(x)).astype('Int64')
```
Expected output: conversion with explicit NaN handling instead of a crash.

## Variant phrasings

### pandas astype int with NaN fails
The canonical case. Nullable Int64 (or fillna first) is the fix.

### Int64 vs int64 pandas
Lowercase int64 is the numpy dtype: no missing values allowed. Capital-I Int64 is pandas nullable extension dtype: integers plus NA. They print almost identically, which is why the error confuses people.

### cannot convert NaN to integer in numpy
Numpy has the same limitation. Use masked arrays, or fill NaN before converting, same idea.

## Why it happens
Numpy's int64 stores raw 64-bit integers with no reserved bit pattern for missing, while float64 reserves NaN. A float column can hold NaN; converting it to int64 has nowhere to put those NaNs, so pandas raises instead of silently dropping them.

## Edge cases
- Nullable Int64 propagates NA through arithmetic (1 + NA = NA); fillna before math if you want zeros.
- Some downstream tools (older sklearn, parquet writers) dont accept Int64; convert to int64 with fillna at the boundary.
- `pd.to_numeric(downcast='integer')` gives numpy int types and will still choke on NaN; downcast after handling missingness.
- String 'nan' vs real NaN: check with `isna()`, not string comparison.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_D7VLc2xZPbd2AsFpw7RM6g
