pandas-dev/pandas · error · ValueError
cannot convert float NaN to integer
Error message
cannot convert float NaN to integer
What it means
Raised in _field_to_int64 when a float-typed year/quarter/day/etc field contains NaN. Casting NaN to int64 would produce a garbage ordinal (a huge negative integer), so pandas explicitly mirrors the scalar Period constructor's error. It guards _range_from_fields' vectorized path.
Source
Thrown at pandas/core/arrays/period.py:1633
ordinals = libperiod.period_ordinals_from_fields(
_field_to_int64(arrays[0]),
_field_to_int64(arrays[1]),
_field_to_int64(arrays[2]),
_field_to_int64(arrays[3]),
_field_to_int64(arrays[4]),
_field_to_int64(arrays[5]),
base,
)
return ordinals, freq
def _field_to_int64(values) -> np.ndarray:
values = np.asarray(values)
if values.dtype.kind == "f" and np.isnan(values).any():
# Match the error raised by the scalar Period constructor; casting
# NaN to int64 would otherwise silently produce garbage ordinals.
raise ValueError("cannot convert float NaN to integer")
return values.astype(np.int64, copy=False)
def _make_field_arrays(*fields) -> list[np.ndarray]:
length = None
for x in fields:
if isinstance(x, (list, tuple, np.ndarray, ABCSeries)):
if length is not None and len(x) != length:
raise ValueError("Mismatched Period array lengths")
if length is None:
length = len(x)
# error: Argument 2 to "repeat" has incompatible type "Optional[int]"; expected
# "Union[Union[int, integer[Any]], Union[bool, bool_], ndarray, Sequence[Union[int,
# integer[Any]]], Sequence[Union[bool, bool_]], Sequence[Sequence[Any]]]"
return [
(
np.asarray(x)View on GitHub (pinned to 71959b8cb9)
Solutions
- Drop or fill NaN rows before building the period range: df = df.dropna(subset=['year']).
- Convert the year column to a nullable Int64 and fill: df['year'] = df['year'].astype('Int64').fillna(0).astype(int).
- Filter to non-null fields: mask = df[['year','quarter']].notna().all(axis=1).
Example fix
// before rng = pd.period_range(year=df['year'], quarter=df['quarter'], freq='Q') // after clean = df.dropna(subset=['year','quarter']) rng = pd.period_range(year=clean['year'].astype(int), quarter=clean['quarter'].astype(int), freq='Q')
Defensive patterns
Strategy: validation
Validate before calling
import pandas as pd
import numpy as np
def period_range_safe(year, quarter, freq='Q'):
y = pd.Series(year)
q = pd.Series(quarter)
mask = y.notna() & q.notna()
return pd.period_range(year=y[mask].astype(int), quarter=q[mask].astype(int), freq=freq) Type guard
def no_nan_float_field(field) -> bool:
import numpy as np
arr = np.asarray(field, dtype=float)
return not np.isnan(arr).any() Try / catch
try:
rng = pd.period_range(year=year, quarter=quarter, freq='Q')
except ValueError as e:
if 'cannot convert float NaN' in str(e):
clean = pd.DataFrame({'y': year, 'q': quarter}).dropna()
rng = pd.period_range(year=clean['y'].astype(int), quarter=clean['q'].astype(int), freq='Q')
else:
raise Prevention
- dropna() on year/quarter columns before constructing periods.
- Prefer nullable Int64 dtypes to detect missing years.
- Avoid float dtypes for year/quarter fields.
When it happens
Trigger: period_range(year=[2020, np.nan], quarter=[1,2], freq='Q'); a year Series with missing values passed to period_range; float columns (e.g. years stored as float64 because of NaNs) reaching the period constructor.
Common situations: CSV years parsed as float because of empty cells; joins/groupbys introducing NaNs into year/quarter columns; nullable integer columns upcast to float by an operation.
Related errors
- start and end must have same freq
- start and end must not be NaT
- Could not infer freq from start/end
- Quarter must be 1 <= q <= 4
- Mismatched Period array lengths
AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07).
Data as JSON: /api/errors/4f37d30f02f23424.
Report an issue: GitHub.