{"record":{"id":"711381b191be5075","repo":"pandas-dev/pandas","slug":"periods-must-be-an-integer-got-periods","errorCode":null,"errorMessage":"periods must be an integer, got {periods}","messagePattern":"periods must be an integer, got (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"pandas/core/arrays/datetimelike.py","lineNumber":2520,"sourceCode":"    \"\"\"\n    If a `periods` argument is passed to the Datetime/Timedelta Array/Index\n    constructor, cast it to an integer.\n\n    Parameters\n    ----------\n    periods : None, int\n\n    Returns\n    -------\n    periods : None or int\n\n    Raises\n    ------\n    TypeError\n        if periods is not None or int\n    \"\"\"\n    if periods is not None and not lib.is_integer(periods):\n        raise TypeError(f\"periods must be an integer, got {periods}\")\n    # error: Incompatible return value type (got \"int | integer[Any] | None\",\n    # expected \"int | None\")\n    return periods  # type: ignore[return-value]\n\n\ndef dtype_to_unit(dtype: DatetimeTZDtype | np.dtype | ArrowDtype) -> str:\n    \"\"\"\n    Return the unit str corresponding to the dtype's resolution.\n\n    Parameters\n    ----------\n    dtype : DatetimeTZDtype or np.dtype\n        If np.dtype, we assume it is a datetime64 dtype.\n\n    Returns\n    -------\n    str\n    \"\"\"","sourceCodeStart":2502,"sourceCodeEnd":2538,"githubUrl":"https://github.com/pandas-dev/pandas/blob/3b7651241d4da534b3559b60ef128e1c34f54116/pandas/core/arrays/datetimelike.py#L2502-L2538","documentation":"Raised by validate_periods when the 'periods' argument is not None and is not an integer (checked via lib.is_integer). date_range / period_range / timedelta_range require periods to be a python int (or numpy integer) because it drives array sizing; floats, strings, or other types are rejected early with a clear message.","triggerScenarios":"Calling pd.date_range(..., periods=value) where value is a float (e.g. 3.0), a numpy float, a string, or any non-integer; same for pd.period_range / pd.timedelta_range which both route through validate_periods.","commonSituations":"Computing periods from a division that yields a float (len(df)/stride); reading a count from JSON/config as a string; numpy scalar that is np.float64 rather than np.int64.","solutions":["Coerce explicitly: periods=int(value) before passing.","Fix the upstream computation to use integer division // or math.ceil with an int cast.","Validate periods is None or isinstance(periods, (int, np.integer)) at the config boundary."],"exampleFix":"// before\npd.date_range('2020-01-01', periods=10/3)  # TypeError: periods must be an integer, got 3.333...\n\n// after\npd.date_range('2020-01-01', periods=int(np.ceil(10/3)))","handlingStrategy":"validation","validationCode":"def coerce_periods(periods):\n    if periods is not None and not isinstance(periods, (int, np.integer)):\n        periods = int(periods)\n    return periods","typeGuard":"def is_valid_periods(p) -> bool:\n    return p is None or isinstance(p, (int, np.integer))","tryCatchPattern":"try:\n    rng = pd.date_range(start=start, periods=periods, freq=freq)\nexcept TypeError as e:\n    if \"periods must be an integer\" in str(e):\n        rng = pd.date_range(start=start, periods=int(periods), freq=freq)\n    else:\n        raise","preventionTips":["Coerce computed counts with int(...) or math.ceil before passing as periods.","Use integer division // for stride math.","Validate config-driven counts at the parse boundary."],"tags":["pandas","date-range","periods","validation","type-error"],"backgroundTag":null,"analyzedSha":"3b7651241d4da534b3559b60ef128e1c34f54116","analyzedAt":"2026-08-11T22:10:44.015Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}