{"record":{"id":"fd40ee485718ad78","repo":"pandas-dev/pandas","slug":"start-and-end-must-have-same-freq","errorCode":null,"errorMessage":"start and end must have same freq","messagePattern":"start and end must have same freq","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"pandas/core/arrays/period.py","lineNumber":1537,"sourceCode":"        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\")\n    if start is NaT or end is NaT:\n        raise ValueError(\"start and end must not be NaT\")\n\n    if freq is None:\n        if is_start_per:\n            freq = start.freq\n        elif is_end_per:\n            freq = end.freq\n        else:  # pragma: no cover\n            raise ValueError(\"Could not infer freq from start/end\")\n        mult = freq.n\n\n    if periods is not None:\n        periods = periods * mult\n        if start is None:\n            data = np.arange(\n                end.ordinal - periods + mult, end.ordinal + 1, mult, dtype=np.int64\n            )","sourceCodeStart":1519,"sourceCodeEnd":1555,"githubUrl":"https://github.com/pandas-dev/pandas/blob/3b7651241d4da534b3559b60ef128e1c34f54116/pandas/core/arrays/period.py#L1519-L1555","documentation":"Raised by _get_ordinal_range when both start and end are Period objects but their .freq attributes differ. Period ranges are uniform-frequency; mixing endpoints of different frequencies has no well-defined result.","triggerScenarios":"pd.period_range(start=pd.Period('2020','A'), end=pd.Period('2020-03','M')); passing two Period scalars of different freq to PeriodIndex start/end.","commonSituations":"Pulling start/end Period values from two different sources that were constructed with different freqs; user-supplied dates parsed with different defaults; migration where one literal changed.","solutions":["Align both endpoints with .asfreq(target_freq) before passing them.","Pass freq= explicitly and use plain strings/timestamps for start/end so pandas harmonizes them.","Normalize at the source: construct both Periods with the same freq literal."],"exampleFix":"# before\npd.period_range(pd.Period('2020','A'), pd.Period('2020-03','M'), freq='M')\n# after\nstart = pd.Period('2020','A').asfreq('M')\npd.period_range(start, pd.Period('2020-03','M'), freq='M')","handlingStrategy":"validation","validationCode":"from pandas import Period\n\ndef endpoints_share_freq(start, end) -> bool:\n    if isinstance(start, Period) and isinstance(end, Period):\n        return start.freq == end.freq\n    return True","typeGuard":"from pandas import Period\n\ndef both_periods_same_freq(start, end) -> bool:\n    return (\n        not (isinstance(start, Period) and isinstance(end, Period))\n        or start.freq == end.freq\n    )","tryCatchPattern":"try:\n    pr = pd.period_range(start=start, end=end, freq=freq)\nexcept ValueError as e:\n    if 'same freq' in str(e) and isinstance(start, pd.Period):\n        pr = pd.period_range(start=start.asfreq(freq), end=end.asfreq(freq), freq=freq)\n    else:\n        raise","preventionTips":["Pass explicit freq= and use string/Timestamp endpoints instead of mixed Period objects.","Normalize both endpoints with .asfreq(target) before range construction.","Construct endpoints in one place with a shared freq literal."],"tags":["pandas","period","freq","range"],"backgroundTag":null,"analyzedSha":"3b7651241d4da534b3559b60ef128e1c34f54116","analyzedAt":"2026-08-11T22:10:44.015Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}