{"record":{"id":"3d2f73b3cfa92f26","repo":"pandas-dev/pandas","slug":"dtype-must-be-perioddtype","errorCode":null,"errorMessage":"dtype must be PeriodDtype","messagePattern":"dtype must be PeriodDtype","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"pandas/core/arrays/period.py","lineNumber":1453,"sourceCode":"\n    Parameters\n    ----------\n    dtype : dtype\n    dtype2 : PeriodDtype or None\n        Dtype derived from a `freq` passed to the caller.\n\n    Returns\n    -------\n    PeriodDtype or None\n\n    Raises\n    ------\n    ValueError : non-period dtype\n    IncompatibleFrequency : mismatch between dtype and freq\n    \"\"\"\n    if dtype is not None:\n        if not isinstance(dtype, PeriodDtype):\n            raise ValueError(\"dtype must be PeriodDtype\")\n        if dtype2 is not None and dtype != dtype2:\n            raise IncompatibleFrequency(\"specified freq and dtype are different\")\n\n    elif dtype2 is not None:\n        if not isinstance(dtype2, PeriodDtype):\n            raise ValueError(\"dtype must be PeriodDtype\")\n        dtype = dtype2\n\n    return dtype\n\n\ndef dt64arr_to_periodarr(\n    data, freq, tz=None\n) -> tuple[npt.NDArray[np.int64], BaseOffset]:\n    \"\"\"\n    Convert a datetime-like array to values Period ordinals.\n\n    Parameters","sourceCodeStart":1435,"sourceCodeEnd":1471,"githubUrl":"https://github.com/pandas-dev/pandas/blob/3b7651241d4da534b3559b60ef128e1c34f54116/pandas/core/arrays/period.py#L1435-L1471","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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]'."],"exampleFix":"# before\npd.PeriodIndex(['2020-01-01'], dtype='datetime64[ns]', freq='D')\n# after\npd.PeriodIndex(['2020-01-01'], freq='D')\n# or\npd.PeriodIndex(['2020-01-01'], dtype=pd.PeriodDtype('D'))","handlingStrategy":"validation","validationCode":"from pandas.api.types import pandas_dtype as _pdtype\nfrom pandas import PeriodDtype\n\ndef ensure_period_dtype(dtype):\n    if dtype is None or isinstance(dtype, PeriodDtype):\n        return dtype\n    raise ValueError(f'dtype must be PeriodDtype, got {dtype!r}')","typeGuard":"from pandas import PeriodDtype\n\ndef is_period_dtype(dtype) -> bool:\n    return isinstance(dtype, PeriodDtype)","tryCatchPattern":"from pandas.errors import IncompatibleFrequency\ntry:\n    idx = pd.PeriodIndex(data, freq=freq, dtype=cand_dtype)\nexcept (ValueError, IncompatibleFrequency) as e:\n    if 'must be PeriodDtype' in str(e):\n        idx = pd.PeriodIndex(data, freq=freq)\n    else:\n        raise","preventionTips":["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."],"tags":["pandas","period","dtype","validation"],"backgroundTag":null,"analyzedSha":"3b7651241d4da534b3559b60ef128e1c34f54116","analyzedAt":"2026-08-11T22:10:44.015Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}