python/cpython · error · ValueError
month must be in 1..12, not {month}
Error message
month must be in 1..12, not {month} What it means
Raised by _check_date_fields() when the month argument to date()/datetime() is not an integer in 1..12. The argument is coerced via __index__ first, so 13, 0, or negative values fail after coercion. This is the standard calendar-range guard for the month field.
Source
Thrown at Lib/_pydatetime.py:575
assert name in ("utcoffset", "dst")
if offset is None:
return
if not isinstance(offset, timedelta):
raise TypeError(f"tzinfo.{name}() must return None "
f"or timedelta, not {type(offset).__name__!r}")
if not -timedelta(1) < offset < timedelta(1):
raise ValueError("offset must be a timedelta "
"strictly between -timedelta(hours=24) and "
f"timedelta(hours=24), not {offset!r}")
def _check_date_fields(year, month, day):
year = _index(year)
month = _index(month)
day = _index(day)
if not MINYEAR <= year <= MAXYEAR:
raise ValueError(f"year must be in {MINYEAR}..{MAXYEAR}, not {year}")
if not 1 <= month <= 12:
raise ValueError(f"month must be in 1..12, not {month}")
dim = _days_in_month(year, month)
if not 1 <= day <= dim:
raise ValueError(f"day {day} must be in range 1..{dim} for month {month} in year {year}")
return year, month, day
def _check_time_fields(hour, minute, second, microsecond, fold):
hour = _index(hour)
minute = _index(minute)
second = _index(second)
microsecond = _index(microsecond)
if not 0 <= hour <= 23:
raise ValueError(f"hour must be in 0..23, not {hour}")
if not 0 <= minute <= 59:
raise ValueError(f"minute must be in 0..59, not {minute}")
if not 0 <= second <= 59:
raise ValueError(f"second must be in 0..59, not {second}")
if not 0 <= microsecond <= 999999:
raise ValueError(f"microsecond must be in 0..999999, not {microsecond}")View on GitHub (pinned to bc6749cc3b)
Solutions
- Convert 0-based months to 1-based (add 1) before constructing date
- Validate month in 1..12 when accepting user input
- Use dateutil.parser or datetime.strptime('%Y-%m-%d') to parse instead of manual splitting
Example fix
// before d = date(2024, js_month, 1) # js_month is 0..11 // after d = date(2024, js_month + 1, 1)
Defensive patterns
Strategy: validation
Validate before calling
if not 1 <= month <= 12:
raise ValueError('month must be 1..12') Type guard
def valid_month(m) -> bool:
return 1 <= m <= 12 Prevention
- Remember Python months are 1-based unlike JavaScript's 0-based getMonth()
- Prefer strptime('%Y-%m-%d') over manual field splitting
When it happens
Trigger: date(2024, 13, 1); date(2024, 0, 5); passing a 0-based month from another API (e.g. JavaScript Date getMonth() returns 0..11) directly to Python's date().
Common situations: Porting JS/Java code where months are 0-based; off-by-one after parsing month strings with a custom map; user-supplied form input like month=13.
Related errors
- day {day} must be in range 1..{dim} for month {month} in yea
- hour must be in 0..23, not {hour}
- minute must be in 0..59, not {minute}
- second must be in 0..59, not {second}
- microsecond must be in 0..999999, not {microsecond}
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/f4ed817f1490063a.
Report an issue: GitHub.