python/cpython · error · ValueError
Invalid week: {week}
Error message
Invalid week: {week} What it means
ISO week numbers must be 1..52, or 53 only in long ISO years (those starting on a Thursday, or leap years starting on a Wednesday — checked via _ymd2ord(year,1,1) % 7). Week 0, week 53 in a short year, or weeks > 53 raise ValueError('Invalid week: N').
Source
Thrown at Lib/_pydatetime.py:529
# tuple[int, int, int] -> tuple[int, int, int] version of date.fromisocalendar
def _isoweek_to_gregorian(year, week, day):
# Year is bounded this way because 9999-12-31 is (9999, 52, 5)
if not MINYEAR <= year <= MAXYEAR:
raise ValueError(f"year must be in {MINYEAR}..{MAXYEAR}, not {year}")
if not 0 < week < 53:
out_of_range = True
if week == 53:
# ISO years have 53 weeks in them on years starting with a
# Thursday and leap years starting on a Wednesday
first_weekday = _ymd2ord(year, 1, 1) % 7
if (first_weekday == 4 or (first_weekday == 3 and
_is_leap(year))):
out_of_range = False
if out_of_range:
raise ValueError(f"Invalid week: {week}")
if not 0 < day < 8:
raise ValueError(f"Invalid weekday: {day} (range is [1, 7])")
# Now compute the offset from (Y, 1, 1) in days:
day_offset = (week - 1) * 7 + (day - 1)
# Calculate the ordinal day for monday, week 1
day_1 = _isoweek1monday(year)
ord_day = day_1 + day_offset
return _ord2ymd(ord_day)
# Just raise TypeError if the arg isn't None or a string.
def _check_tzname(name):
if name is not None and not isinstance(name, str):
raise TypeError("tzinfo.tzname() must return None or string, "View on GitHub (pinned to bc6749cc3b)
Solutions
- Derive the max week from the calendar itself: max_week = date(y, 12, 28).isocalendar()[1] and validate against it
- When incrementing weeks, recompute from the resulting date: d += timedelta(weeks=1); y, w, dd = d.isocalendar()
- Reject week 0 and week 53 early unless the long-year check passes
Example fix
// before d = date.fromisocalendar(2021, 53, 1) # ValueError: 2021 has 52 weeks # after from datetime import date, timedelta d = date(2021, 1, 4) + timedelta(weeks=52) # step from a known week-1 Monday # or validate: assert week <= date(year, 12, 28).isocalendar()[1]
Defensive patterns
Strategy: validation
Validate before calling
from datetime import date
def max_iso_week(year: int) -> int:
return date(year, 12, 28).isocalendar()[1] # Dec 28 is always in the last week
def check_week(year: int, week: int) -> None:
if not 1 <= week <= max_iso_week(year):
raise ValueError(f'week {week} invalid for {year} (max {max_iso_week(year)})') Type guard
def is_valid_iso_week(year: int, week: int) -> bool:
return 1 <= week <= date(year, 12, 28).isocalendar()[1] Try / catch
try:
d = date.fromisocalendar(y, w, wd)
except ValueError:
d = None # clamp/skip and log the offending record Prevention
- Never assume 53 weeks; compute the year's max via Dec 28
- When rolling weeks forward, recompute y/w from the resulting date
- Validate week 0 from external input early
When it happens
Trigger: date.fromisocalendar(2021, 53, 1) (2021 has 52 ISO weeks); fromisocalendar(2021, 0, 1); week computed as last_week + 1 rolling past year end without incrementing the ISO year.
Common situations: Off-by-one when iterating weeks across year boundaries; user input assuming every year has 53 weeks; reporting software that increments week without checking date.isocalendar() of Dec 28 (the week-count pivot); week 53 hard-coded for fiscal calendars.
Related errors
- year must be in {MINYEAR}..{MAXYEAR}, not {year}
- Invalid weekday: {day} (range is [1, 7])
- Invalid ISO string
- Inconsistent use of dash separator
- Unknown timespec value
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/21cee14f6a74929b.
Report an issue: GitHub.