{"record":{"id":"fe165c888dee46e4","repo":"python/cpython","slug":"invalid-isoformat-string","errorCode":null,"errorMessage":"Invalid isoformat string","messagePattern":"Invalid isoformat string","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"Lib/_pydatetime.py","lineNumber":362,"sourceCode":"\n            if idx < 9:\n                return idx\n\n            if idx % 2 == 0:\n                # If the index of the last number is even, it's YYYYWwwd\n                return 7\n            else:\n                return 8\n        else:\n            # YYYYMMDD (8)\n            return 8\n\n\ndef _parse_isoformat_date(dtstr):\n    # It is assumed that this is an ASCII-only string of lengths 7, 8 or 10,\n    # see the comment on Modules/_datetimemodule.c:_find_isoformat_datetime_separator\n    if len(dtstr) not in (7, 8, 10):\n        raise ValueError(\"Invalid isoformat string\")\n    year = int(dtstr[0:4])\n    has_sep = dtstr[4] == '-'\n\n    pos = 4 + has_sep\n    if dtstr[pos:pos + 1] == \"W\":\n        # YYYY-?Www-?D?\n        pos += 1\n        weekno = int(dtstr[pos:pos + 2])\n        pos += 2\n\n        dayno = 1\n        if len(dtstr) > pos:\n            if (dtstr[pos:pos + 1] == '-') != has_sep:\n                raise ValueError(\"Inconsistent use of dash separator\")\n\n            pos += has_sep\n\n            dayno = int(dtstr[pos:pos + 1])","sourceCodeStart":344,"sourceCodeEnd":380,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_pydatetime.py#L344-L380","documentation":"_parse_isoformat_date accepts only date strings of length 7 (YYYY-Www), 8 (YYYYMMDD or YYYY-Www compact variants) or 10 (YYYY-MM-DD). Any other length raises ValueError('Invalid isoformat string') before any digits are inspected, so the content cannot matter yet.","triggerScenarios":"datetime.fromisoformat('2021-1-1') (length 8 but invalid shape reaches other errors; here e.g. '202101011' length 9, '2021' length 4, '2021-0101' etc.); passing a full datetime string to date.fromisoformat on older Pythons; passing a time-only string like '12:30'.","commonSituations":"Assuming fromisoformat is a general ISO-8601 parser (it is strict and, pre-3.11, only accepts datetime.isoformat() output); lenient user input with missing zero padding; mixing date.fromisoformat and datetime.fromisoformat on the wrong value.","solutions":["Normalize input to YYYY-MM-DD (or the exact inverse of date.isoformat()) before parsing","Zero-pad components when constructing strings: f'{y:04d}-{m:02d}-{d:02d}'","For arbitrary ISO-8601 input use dateutil.parser.isoparse instead of fromisoformat"],"exampleFix":"// before\nd = date.fromisoformat(user_input)  # '2021-1-1' -> ValueError\n\n# after\nfrom datetime import datetime\nd = datetime.strptime(user_input, '%Y-%m-%d').date()","handlingStrategy":"validation","validationCode":"import re\n_DATE_RE = re.compile(r'^\\d{4}-\\d{2}-\\d{2}$|^\\d{8}$')\ndef parse_date(s: str):\n    if not _DATE_RE.fullmatch(s):\n        raise ValueError(f'expected YYYY-MM-DD or YYYYMMDD, got {s!r}')\n    return date.fromisoformat(s)","typeGuard":"def looks_like_iso_date(s: str) -> bool:\n    return len(s) in (8, 10) and s[:4].isdigit() and s.endswith(tuple('0123456789'))","tryCatchPattern":"try:\n    d = date.fromisoformat(s)\nexcept ValueError:\n    d = datetime.strptime(s, '%Y-%m-%d').date()  # stricter, better message","preventionTips":["Remember fromisoformat parses only datetime.isoformat output (pre-3.11), not all of ISO-8601","Zero-pad generated date strings","Use dateutil for arbitrary user input"],"tags":["datetime","fromisoformat","isoformat","valueerror","stdlib"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}