{"record":{"id":"35c99bd70bdf9a8b","repo":"pandas-dev/pandas","slug":"of-the-three-parameters-start-end-and-periods","errorCode":null,"errorMessage":"Of the three parameters: start, end, and periods, exactly two must be specified","messagePattern":"Of the three parameters: start, end, and periods, exactly two must be specified","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"pandas/core/arrays/period.py","lineNumber":1519,"sourceCode":"                    \"Pass `freq` explicitly instead.\",\n                    Pandas4Warning,\n                    stacklevel=find_stack_level(),\n                )\n                freq = inferred_freq\n            data = data._values\n\n    elif isinstance(data, (ABCIndex, ABCSeries)):\n        data = data._values\n\n    reso = get_unit_from_dtype(data.dtype)\n    freq = Period._maybe_convert_freq(freq)\n    base = freq._period_dtype_code\n    return c_dt64arr_to_periodarr(data.view(\"i8\"), base, tz, reso=reso), freq\n\n\ndef _get_ordinal_range(start, end, periods, freq, mult: int = 1):\n    if com.count_not_none(start, end, periods) != 2:\n        raise ValueError(\n            \"Of the three parameters: start, end, and periods, \"\n            \"exactly two must be specified\"\n        )\n\n    if freq is not None:\n        freq = to_offset(freq, is_period=True)\n        mult = freq.n\n\n    if start is not None:\n        start = Period(start, freq)\n    if end is not None:\n        end = Period(end, freq)\n\n    is_start_per = isinstance(start, Period)\n    is_end_per = isinstance(end, Period)\n\n    if is_start_per and is_end_per and start.freq != end.freq:\n        raise ValueError(\"start and end must have same freq\")","sourceCodeStart":1501,"sourceCodeEnd":1537,"githubUrl":"https://github.com/pandas-dev/pandas/blob/3b7651241d4da534b3559b60ef128e1c34f54116/pandas/core/arrays/period.py#L1501-L1537","documentation":"Raised by _get_ordinal_range (used by period_range and PeriodIndex construction) when count_not_none(start, end, periods) != 2. Exactly two of the three must be supplied so the range endpoints are unambiguous.","triggerScenarios":"Calling pd.period_range(start=..., end=..., periods=...) with all three; with only one; or with none. Same family of misuse as date_range's equivalent guard.","commonSituations":"Dynamic code where some of start/end/periods come from optional user input and default to None; copy-paste from a date_range call that added a third argument; off-by-one in argument plumbing.","solutions":["Pass exactly two of start, end, periods.","Gate inputs: pick end+periods when start is None, start+end otherwise.","Default missing values explicitly so exactly two are non-None at the call site."],"exampleFix":"# before\npd.period_range(start='2020', end='2021', periods=12, freq='M')\n# after\npd.period_range(start='2020', end='2021', freq='M')  # let pandas count","handlingStrategy":"validation","validationCode":"from pandas.core.common import count_not_none\n\ndef exactly_two_of_three(start, end, periods) -> bool:\n    return count_not_none(start, end, periods) == 2","typeGuard":"def valid_range_args(start, end, periods) -> bool:\n    return sum(x is not None for x in (start, end, periods)) == 2","tryCatchPattern":"try:\n    pr = pd.period_range(start=start, end=end, periods=periods, freq=freq)\nexcept ValueError as e:\n    if 'exactly two' in str(e):\n        raise ValueError('Supply exactly two of start/end/periods') from e\n    raise","preventionTips":["Compute your own (start, end, periods) and assert exactly two are non-None.","Centralize period_range calls in one helper that enforces the rule.","Beware optional user inputs that default to None."],"tags":["pandas","period","range","validation"],"backgroundTag":null,"analyzedSha":"3b7651241d4da534b3559b60ef128e1c34f54116","analyzedAt":"2026-08-11T22:10:44.015Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}