pandas-dev/pandas · error · ValueError
start and end must not be NaT
Error message
start and end must not be NaT
What it means
Raised by _get_ordinal_range when start or end resolves to pandas.NaT. A period range needs concrete endpoints; NaT cannot anchor or terminate it.
Solutions
- Filter NaT out of inputs before constructing the range.
- Replace NaT with a concrete fallback date or use try/except around parsing.
- Validate with pd.notna() before passing endpoints.
Example fix
# before
start = pd.to_datetime(maybe_bad, errors='coerce')
pd.period_range(start, end, freq='D')
# after
start = pd.to_datetime(maybe_bad, errors='coerce')
if pd.isna(start):
raise ValueError(f'unparseable start: {maybe_bad!r}')
pd.period_range(start, end, freq='D') Defensive patterns
Strategy: validation
Validate before calling
import pandas as pd
def endpoints_not_nat(start, end) -> bool:
return pd.notna(start) and pd.notna(end) Type guard
def is_usable_endpoint(value) -> bool:
return value is not None and not (isinstance(value, float) and value != value) and not pd.isna(value) Try / catch
try:
pr = pd.period_range(start=start, end=end, freq=freq)
except ValueError as e:
if 'must not be NaT' in str(e):
start = start if pd.notna(start) else fallback_start
end = end if pd.notna(end) else fallback_end
pr = pd.period_range(start=start, end=end, freq=freq)
else:
raise Prevention
- pd.notna(value) every endpoint before passing it.
- Avoid errors='coerce' in parsing if you cannot tolerate NaT.
- Drop rows with NaT dates upstream of range construction.
When it happens
Trigger: Passing start=pd.NaT or end=pd.NaT to period_range; feeding Period values derived from un-parseable strings (which become NaT) into the range builder.
Common situations: Dirty input data with missing/blank date fields converted via pd.to_datetime(errors='coerce'); conditional code that sometimes yields NaT; downstream of failed parsing silently producing NaT.
Related errors
- dtype must be PeriodDtype
- Mismatched Period array lengths
- Neither `start` nor `end` can be NaT
- Not enough parameters to construct Period range
- Of the three parameters: start, end, and periods, exactly…
AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11).
Data as JSON: /api/errors/257a62cf3a6f714b.
Report an issue: GitHub.
Appendix: source
Thrown at pandas/core/arrays/period.py:1539
"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
)
else:
data = np.arange(View on GitHub (pinned to 3b7651241d)