pandas-dev/pandas · error · ValueError
Neither `start` nor `end` can be NaT
Error message
Neither `start` nor `end` can be NaT
What it means
Raised by DatetimeArray._generate_range after coercing start/end to Timestamp when either is pd.NaT. Generating a range from a not-a-time boundary is impossible (the step math has no anchor), so it is rejected before unit/freq resolution proceeds.
Solutions
- Validate start/end before the call: if pd.isna(start) or pd.isna(end): handle missing-boundary case.
- Clean or filter NaT from the source column before passing its first/last value.
- Use try/except around the parse to substitute a default Timestamp when input is missing.
Example fix
// before
start = pd.to_datetime('') # NaT
pd.date_range(start, periods=5, freq='D') # ValueError: Neither start nor end can be NaT
// after
start = pd.to_datetime(user_input) if user_input else pd.Timestamp('2020-01-01')
pd.date_range(start, periods=5, freq='D') Defensive patterns
Strategy: validation
Validate before calling
def safe_range_bound(bound):
ts = pd.Timestamp(bound)
if pd.isna(ts):
raise ValueError(f"boundary {bound!r} parsed to NaT")
return ts Type guard
def is_valid_range_bound(bound) -> bool:
return not pd.isna(pd.Timestamp(bound)) if bound is not None else False Try / catch
try:
rng = pd.date_range(start=start, periods=5, freq="D")
except ValueError as e:
if "can be NaT" in str(e):
start = pd.Timestamp.today().normalize()
rng = pd.date_range(start=start, periods=5, freq="D")
else:
raise Prevention
- Validate pd.isna on start/end before calling date_range.
- Filter NaT from source columns before taking their first/last value.
- Default missing bounds to a sensible Timestamp, not None-through-NaT.
When it happens
Trigger: pd.date_range(start=pd.NaT, periods=5, freq='D'); pd.date_range(end=pd.NaT, ...); passing a column value that parsed to NaT (e.g. empty string, unparseable date) as start or end.
Common situations: Reading start/end from user input or config that may be blank; selecting index[0] from an index that contains NaT; chaining date_range to upstream parsing that can yield NaT.
Related errors
- Must provide freq argument if no data is supplied
- Of the four parameters: start, end, periods, and freq…
- periods must be an integer, got
- start and end must not be NaT
- 'unit' must be one of 's', 'ms', 'us', 'ns'
AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11).
Data as JSON: /api/errors/d009742cfc2edad8.
Report an issue: GitHub.
Appendix: source
Thrown at pandas/core/arrays/datetimes.py:422
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:
unit = "ns"
if start is not None:
start = start.as_unit(unit, round_ok=False)
if end is not None:
end = end.as_unit(unit, round_ok=False)
left_inclusive, right_inclusive = validate_inclusive(inclusive)
start, end = _maybe_normalize_endpoints(start, end, normalize)
tz = _infer_tz_from_endpoints(start, end, tz)
if tz is not None:
# Localize the start and end argumentsView on GitHub (pinned to 3b7651241d)