RustPython/RustPython · error · ValueError
Invalid ISO string
Error message
Invalid ISO string
What it means
_find_isoformat_datetime_separator is the internal helper that decides where the date portion of a fromisoformat string ends. In the ISO week-date branch (dtstr[5] == 'W'), a string too short to still contain the two-digit week number (len_dtstr < 8) is rejected with ValueError('Invalid ISO string'). The branch is largely shielded by the len == 7 early return and the following assert, so it mainly bites degenerate inputs like '2019-W', especially under python -O where asserts are stripped.
Source
Thrown at Lib/_pydatetime.py:314
# Helpers for parsing the result of isoformat()
def _is_ascii_digit(c):
return c in "0123456789"
def _find_isoformat_datetime_separator(dtstr):
# See the comment in _datetimemodule.c:_find_isoformat_datetime_separator
len_dtstr = len(dtstr)
if len_dtstr == 7:
return 7
assert len_dtstr > 7
date_separator = "-"
week_indicator = "W"
if dtstr[4] == date_separator:
if dtstr[5] == week_indicator:
if len_dtstr < 8:
raise ValueError("Invalid ISO string")
if len_dtstr > 8 and dtstr[8] == date_separator:
if len_dtstr == 9:
raise ValueError("Invalid ISO string")
if len_dtstr > 10 and _is_ascii_digit(dtstr[10]):
# This is as far as we need to resolve the ambiguity for
# the moment - if we have YYYY-Www-##, the separator is
# either a hyphen at 8 or a number at 10.
#
# We'll assume it's a hyphen at 8 because it's way more
# likely that someone will use a hyphen as a separator than
# a number, but at this point it's really best effort
# because this is an extension of the spec anyway.
# TODO(pganssle): Document this
return 8
return 10
else:
# YYYY-Www (8)
return 8View on GitHub (pinned to aaeab4f754)
Solutions
- Emit the full week date: '2019-W01' (len 8) or '2019W01'
- Validate the shape with a regex like ^\d{4}-?W\d{2}$ before calling fromisoformat
- Wrap fromisoformat in try/except ValueError and reject the field at the input boundary
Example fix
# before
date.fromisoformat('2019-W') # Invalid ISO string
# after
date.fromisoformat('2019-W01') # datetime.date(2019, 1, 7) Defensive patterns
Strategy: try-catch
Validate before calling
import re
ISO_WEEK_DATE = re.compile(r'^\d{4}-?W\d{2}(-?\d)?$')
if not ISO_WEEK_DATE.match(s):
raise ValueError(f'not a valid ISO week date: {s!r}')
d = date.fromisoformat(s) Try / catch
try:
d = date.fromisoformat(s)
except (ValueError, AssertionError):
raise ValueError(f'malformed ISO date: {s!r}') from None Prevention
- Always emit full ISO week dates ('2019-W01'), never truncated fragments
- Generate strings via date(...).isocalendar() + formatting instead of manual assembly
- Validate shape with a regex at the ingestion boundary
When it happens
Trigger: date.fromisoformat('2019-W') or datetime.fromisoformat('2019-W') — a week indicator with no room for the mandatory two-digit week number. Without -O this typically surfaces as an AssertionError from the guard instead.
Common situations: Truncated date fields from CSV/log ingestion; hand-assembled ISO week strings; tests feeding partial strings to check parser behavior.
Related errors
- Inconsistent use of dash separator
- Incomplete time component
- Invalid time separator: %c
- Invalid microsecond separator
- Non-digit values in fraction
AI-assisted analysis of RustPython/RustPython@aaeab4f754 (2026-08-17).
Data as JSON: /api/errors/c3606f2ebc40885f.
Report an issue: GitHub.