{"record":{"id":"c3606f2ebc40885f","repo":"RustPython/RustPython","slug":"invalid-iso-string","errorCode":null,"errorMessage":"Invalid ISO string","messagePattern":"Invalid ISO string","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"Lib/_pydatetime.py","lineNumber":314,"sourceCode":"\n# Helpers for parsing the result of isoformat()\ndef _is_ascii_digit(c):\n    return c in \"0123456789\"\n\ndef _find_isoformat_datetime_separator(dtstr):\n    # See the comment in _datetimemodule.c:_find_isoformat_datetime_separator\n    len_dtstr = len(dtstr)\n    if len_dtstr == 7:\n        return 7\n\n    assert len_dtstr > 7\n    date_separator = \"-\"\n    week_indicator = \"W\"\n\n    if dtstr[4] == date_separator:\n        if dtstr[5] == week_indicator:\n            if len_dtstr < 8:\n                raise ValueError(\"Invalid ISO string\")\n            if len_dtstr > 8 and dtstr[8] == date_separator:\n                if len_dtstr == 9:\n                    raise ValueError(\"Invalid ISO string\")\n                if len_dtstr > 10 and _is_ascii_digit(dtstr[10]):\n                    # This is as far as we need to resolve the ambiguity for\n                    # the moment - if we have YYYY-Www-##, the separator is\n                    # either a hyphen at 8 or a number at 10.\n                    #\n                    # We'll assume it's a hyphen at 8 because it's way more\n                    # likely that someone will use a hyphen as a separator than\n                    # a number, but at this point it's really best effort\n                    # because this is an extension of the spec anyway.\n                    # TODO(pganssle): Document this\n                    return 8\n                return 10\n            else:\n                # YYYY-Www (8)\n                return 8","sourceCodeStart":296,"sourceCodeEnd":332,"githubUrl":"https://github.com/RustPython/RustPython/blob/aaeab4f754b4f40efc0c8ab39cf7c4a3c35a8cfd/Lib/_pydatetime.py#L296-L332","documentation":"_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.","triggerScenarios":"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.","commonSituations":"Truncated date fields from CSV/log ingestion; hand-assembled ISO week strings; tests feeding partial strings to check parser behavior.","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"],"exampleFix":"# before\ndate.fromisoformat('2019-W')  # Invalid ISO string\n\n# after\ndate.fromisoformat('2019-W01')  # datetime.date(2019, 1, 7)","handlingStrategy":"try-catch","validationCode":"import re\nISO_WEEK_DATE = re.compile(r'^\\d{4}-?W\\d{2}(-?\\d)?$')\nif not ISO_WEEK_DATE.match(s):\n    raise ValueError(f'not a valid ISO week date: {s!r}')\nd = date.fromisoformat(s)","typeGuard":null,"tryCatchPattern":"try:\n    d = date.fromisoformat(s)\nexcept (ValueError, AssertionError):\n    raise ValueError(f'malformed ISO date: {s!r}') from None","preventionTips":["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"],"tags":["datetime","iso8601","fromisoformat","valueerror","parse-error","week-date"],"backgroundTag":"iso8601-parse-error","analyzedSha":"aaeab4f754b4f40efc0c8ab39cf7c4a3c35a8cfd","analyzedAt":"2026-08-17T00:37:52.100Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}