pandas-dev/pandas · error · ValueError

Of the three parameters: start, end, and periods, exactly tw

Error message

Of the three parameters: start, end, and periods, exactly two must be specified

What it means

Raised by _get_ordinal_range when com.count_not_none(start, end, periods) != 2. A period range is fully determined by exactly two of {start, end, periods} together with freq; supplying all three is over-determined and supplying fewer than two is under-determined, both rejected.

Source

Thrown at pandas/core/arrays/period.py:1516

                    "Pass `freq` explicitly instead.",
                    Pandas4Warning,
                    stacklevel=find_stack_level(),
                )
                freq = inferred_freq
            data = data._values

    elif isinstance(data, (ABCIndex, ABCSeries)):
        data = data._values

    reso = get_unit_from_dtype(data.dtype)
    freq = Period._maybe_convert_freq(freq)
    base = freq._period_dtype_code
    return c_dt64arr_to_periodarr(data.view("i8"), base, tz, reso=reso), freq


def _get_ordinal_range(start, end, periods, freq, mult: int = 1):
    if com.count_not_none(start, end, periods) != 2:
        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")

View on GitHub (pinned to 71959b8cb9)

Solutions

  1. Pass exactly two: start + end, start + periods, or end + periods.
  2. Drop the redundant parameter if all three are set.
  3. Compute the missing one upstream and pass exactly two.

Example fix

# before
pd.period_range(start='2020-01-01', end='2020-01-05', periods=5, freq='D')
# after
pd.period_range(start='2020-01-01', end='2020-01-05', freq='D')
# or
pd.period_range(start='2020-01-01', periods=5, freq='D')
Defensive patterns

Strategy: validation

Validate before calling

import pandas as pd

def exactly_two_of(start, end, periods, freq):
    provided = sum(x is not None for x in (start, end, periods))
    if provided != 2:
        raise ValueError(f'Exactly two of start/end/periods required, got {provided}')
    return pd.period_range(start=start, end=end, periods=periods, freq=freq)

Type guard

def has_exactly_two_anchors(start, end, periods) -> bool:
    return sum(x is not None for x in (start, end, periods)) == 2

Try / catch

try:
    rng = pd.period_range(start=start, end=end, periods=periods, freq=freq)
except ValueError:
    # drop periods if start and end are both set
    rng = pd.period_range(start=start, end=end, freq=freq)

Prevention

When it happens

Trigger: pd.period_range(start=..., end=..., periods=...) (all three); pd.period_range(freq='D') (none of the three); pd.period_range(start='2020-01-01', freq='D') (only one).

Common situations: Dynamic config where all three fields default to provided values. Refactors that accidentally pass periods alongside start+end. UI forms exposing all three fields.

Related errors


AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07). Data as JSON: /api/errors/35c99bd70bdf9a8b. Report an issue: GitHub.