pandas-dev/pandas · error · ValueError
dtype must be PeriodDtype
Error message
dtype must be PeriodDtype
What it means
Raised by pandas.core.arrays.period.validate_dtype_freq when an explicitly passed dtype is non-None but is not a PeriodDtype instance. Period arrays require their dtype to carry a frequency, so a plain dtype like 'int64' or 'datetime64[ns]' is rejected at construction. The check guards the dtype branch (dtype is not None) before any freq reconciliation happens.
Solutions
- Drop the dtype argument entirely and let pandas infer PeriodDtype from freq or from the Period objects.
- Pass dtype as a PeriodDtype constructed via pd.PeriodDtype(freq) e.g. pd.PeriodDtype('D').
- If you only have a freq string, pass freq='D' instead of dtype='datetime64[ns]'.
Example fix
# before
pd.PeriodIndex(['2020-01-01'], dtype='datetime64[ns]', freq='D')
# after
pd.PeriodIndex(['2020-01-01'], freq='D')
# or
pd.PeriodIndex(['2020-01-01'], dtype=pd.PeriodDtype('D')) Defensive patterns
Strategy: validation
Validate before calling
from pandas.api.types import pandas_dtype as _pdtype
from pandas import PeriodDtype
def ensure_period_dtype(dtype):
if dtype is None or isinstance(dtype, PeriodDtype):
return dtype
raise ValueError(f'dtype must be PeriodDtype, got {dtype!r}') Type guard
from pandas import PeriodDtype
def is_period_dtype(dtype) -> bool:
return isinstance(dtype, PeriodDtype) Try / catch
from pandas.errors import IncompatibleFrequency
try:
idx = pd.PeriodIndex(data, freq=freq, dtype=cand_dtype)
except (ValueError, IncompatibleFrequency) as e:
if 'must be PeriodDtype' in str(e):
idx = pd.PeriodIndex(data, freq=freq)
else:
raise Prevention
- Always pass freq= and let PeriodDtype be derived instead of passing dtype=.
- Validate dtype with isinstance(dtype, pd.PeriodDtype) before constructing PeriodIndex.
- Avoid copy-pasting dtype kwargs from DatetimeIndex code.
When it happens
Trigger: Constructing PeriodArray/PeriodIndex/period_range with dtype= something that is not PeriodDtype (e.g. dtype='int64', dtype=np.int64, dtype='datetime64[ns]', dtype='object'). Passing a pandas_dtype that resolves to a non-Period extension or numpy dtype while freq is also given.
Common situations: Mistakenly thinking PeriodIndex is built from datetime64 dtype; copy-pasting dtype from a DatetimeIndex workflow; constructing PeriodArray from a list of Period objects and supplying a stray dtype keyword from a generic helper.
Related errors
- does not have a resolution.
- dtype is not specified and cannot be inferred
- Incorrect dtype
- Invalid dtype for PeriodArray
- Mismatched Period array lengths
AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11).
Data as JSON: /api/errors/3d2f73b3cfa92f26.
Report an issue: GitHub.
Appendix: source
Thrown at pandas/core/arrays/period.py:1453
Parameters
----------
dtype : dtype
dtype2 : PeriodDtype or None
Dtype derived from a `freq` passed to the caller.
Returns
-------
PeriodDtype or None
Raises
------
ValueError : non-period dtype
IncompatibleFrequency : mismatch between dtype and freq
"""
if dtype is not None:
if not isinstance(dtype, PeriodDtype):
raise ValueError("dtype must be PeriodDtype")
if dtype2 is not None and dtype != dtype2:
raise IncompatibleFrequency("specified freq and dtype are different")
elif dtype2 is not None:
if not isinstance(dtype2, PeriodDtype):
raise ValueError("dtype must be PeriodDtype")
dtype = dtype2
return dtype
def dt64arr_to_periodarr(
data, freq, tz=None
) -> tuple[npt.NDArray[np.int64], BaseOffset]:
"""
Convert a datetime-like array to values Period ordinals.
ParametersView on GitHub (pinned to 3b7651241d)