pandas-dev/pandas · error · ValueError
start and end must have same freq
Error message
start and end must have same freq
What it means
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.
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.
Example fix
# before
pd.period_range(pd.Period('2020','A'), pd.Period('2020-03','M'), freq='M')
# after
start = pd.Period('2020','A').asfreq('M')
pd.period_range(start, pd.Period('2020-03','M'), freq='M') Defensive patterns
Strategy: validation
Validate before calling
from pandas import Period
def endpoints_share_freq(start, end) -> bool:
if isinstance(start, Period) and isinstance(end, Period):
return start.freq == end.freq
return True Type guard
from pandas import Period
def both_periods_same_freq(start, end) -> bool:
return (
not (isinstance(start, Period) and isinstance(end, Period))
or start.freq == end.freq
) Try / catch
try:
pr = pd.period_range(start=start, end=end, freq=freq)
except ValueError as e:
if 'same freq' in str(e) and isinstance(start, pd.Period):
pr = pd.period_range(start=start.asfreq(freq), end=end.asfreq(freq), freq=freq)
else:
raise Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Could not infer freq from start/end
- Cannot add or subtract timedelta64[ns] dtype from
- Cannot add/subtract timedelta-like from PeriodArray that is…
- dtype is not specified and cannot be inferred
- freq must be a quarterly frequency
AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11).
Data as JSON: /api/errors/fd40ee485718ad78.
Report an issue: GitHub.
Appendix: source
Thrown at pandas/core/arrays/period.py:1537
raise ValueError(
"Of the three parameters: start, end, and periods, "
"exactly two must be specified"
)
if freq is not None:
freq = to_offset(freq, is_period=True)
mult = freq.n
if start is not None:
start = Period(start, freq)
if end is not None:
end = Period(end, freq)
is_start_per = isinstance(start, Period)
is_end_per = isinstance(end, Period)
if is_start_per and is_end_per and start.freq != end.freq:
raise ValueError("start and end must have same freq")
if start is NaT or end is NaT:
raise ValueError("start and end must not be NaT")
if freq is None:
if is_start_per:
freq = start.freq
elif is_end_per:
freq = end.freq
else: # pragma: no cover
raise ValueError("Could not infer freq from start/end")
mult = freq.n
if periods is not None:
periods = periods * mult
if start is None:
data = np.arange(
end.ordinal - periods + mult, end.ordinal + 1, mult, dtype=np.int64
)View on GitHub (pinned to 3b7651241d)