pandas-dev/pandas · error · ValueError

cannot convert float NaN to integer

Error message

cannot convert float NaN to integer

What it means

Raised by _field_to_int64 when the input array has float dtype and contains NaN. Casting NaN to int64 silently yields a garbage ordinal, so pandas refuses, matching the scalar Period constructor's behavior.

Solutions

  1. Drop or impute missing field values before constructing the PeriodIndex.
  2. Use fillna on the offending column with a sensible default or dropna() the rows.
  3. If missingness is meaningful, build a PeriodIndex for the valid subset and reindex.

Example fix

# before
year = df['year'].astype(float)  # contains NaN
pd.PeriodIndex(year=year, quarter=df['q'], freq='Q')
# after
mask = df['year'].notna()
pd.PeriodIndex(year=df.loc[mask,'year'].astype(int), quarter=df.loc[mask,'q'], freq='Q')
Defensive patterns

Strategy: validation

Validate before calling

import numpy as np

def fields_are_castable_to_int(values) -> bool:
    arr = np.asarray(values)
    if arr.dtype.kind == 'f':
        return not np.isnan(arr).any()
    return True

Type guard

def has_no_nan_float(values) -> bool:
    arr = np.asarray(values)
    return arr.dtype.kind != 'f' or not bool(np.isnan(arr).any())

Try / catch

try:
    pi = pd.PeriodIndex(year=y, quarter=q, freq='Q')
except ValueError as e:
    if 'cannot convert float NaN' in str(e):
        mask = np.asarray(y, dtype=float) == np.asarray(y, dtype=float)
        pi = pd.PeriodIndex(year=np.asarray(y)[mask], quarter=np.asarray(q)[mask], freq='Q')
    else:
        raise

Prevention

When it happens

Trigger: Passing a year/month/quarter/hour/... field built from a float column with missing values to PeriodIndex field-based construction; year = pd.Series([2020.0, np.nan]) used as the year field.

Common situations: Joining onto a dimension table that left nulls; user-uploaded spreadsheets with blank cells; downstream of merge that introduced NaNs.

Related errors


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

Appendix: source

Thrown at pandas/core/arrays/period.py:1636

        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 3b7651241d)