pandas-dev/pandas · error · ValueError

Of the four parameters: start, end, periods, and freq…

Error message

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

What it means

Raised by DatetimeArray._generate_range when com.count_not_none(start, end, periods, freq) != 3. The generator requires exactly three of the four parameters so the fourth is unambiguously inferred; providing two, all four, or only one is rejected. Note this fires after the 'freq missing' guard, so freq is already non-None when reached.

Solutions

  1. Provide exactly three: start+end+freq, start+end+periods, start+periods+freq, or end+periods+freq.
  2. If you have start and end only, omit one of periods/freq intentionally and pass the other.
  3. Use com.count_not_none(start,end,periods,freq)==3 as an upstream assert.

Example fix

// before
pd.date_range('2020-01-01', '2020-01-10')  # ValueError: exactly three must be specified

// after
pd.date_range('2020-01-01', '2020-01-10', freq='D')  # periods inferred
Defensive patterns

Strategy: validation

Validate before calling

def safe_date_range(start=None, end=None, periods=None, freq=None):
    n = sum(x is not None for x in [start, end, periods, freq])
    if n != 3:
        raise ValueError(f"Need exactly 3 of start/end/periods/freq, got {n}")
    return pd.date_range(start=start, end=end, periods=periods, freq=freq)

Type guard

def exactly_three_of_four(start, end, periods, freq) -> bool:
    return sum(x is not None for x in [start, end, periods, freq]) == 3

Try / catch

try:
    rng = pd.date_range(start=start, end=end, periods=periods, freq=freq)
except ValueError as e:
    if "exactly three must be specified" in str(e):
        # drop one arg or supply the missing one intentionally
        rng = pd.date_range(start=start, end=end, freq="D")
    else:
        raise

Prevention

When it happens

Trigger: pd.date_range(start, end) with neither periods nor freq (only two of four); pd.date_range(start, end, periods, freq) supplying all four; pd.date_range(start, freq) with two None.

Common situations: Over-specifying after a refactor (adding periods while keeping freq); under-specifying when freq defaults to None; conditional logic that sometimes leaves two args set.

Related errors


AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11). Data as JSON: /api/errors/06a36309b8c68fdb. Report an issue: GitHub.

Appendix: source

Thrown at pandas/core/arrays/datetimes.py:409

        cls,
        start,
        end,
        periods: int | None,
        freq,
        tz=None,
        normalize: bool = False,
        ambiguous: TimeAmbiguous = "raise",
        nonexistent: TimeNonexistent = "raise",
        inclusive: IntervalClosedType = "both",
        *,
        unit: TimeUnit = "ns",
    ) -> Self:
        periods = dtl.validate_periods(periods)
        if freq is None and any(x is None for x in [periods, start, end]):
            raise ValueError("Must provide freq argument if no data is supplied")

        if com.count_not_none(start, end, periods, freq) != 3:
            raise ValueError(
                "Of the four parameters: start, end, periods, "
                "and freq, exactly three must be specified"
            )
        freq = to_offset(freq)

        if start is not None:
            start = Timestamp(start)

        if end is not None:
            end = Timestamp(end)

        if start is NaT or end is NaT:
            raise ValueError("Neither `start` nor `end` can be NaT")

        if unit is not None:
            if unit not in ["s", "ms", "us", "ns"]:
                raise ValueError("'unit' must be one of 's', 'ms', 'us', 'ns'")
        else:

View on GitHub (pinned to 3b7651241d)