{"record":{"id":"f35c5e300ea46d62","repo":"666ghj/MiroFish","slug":"reconstruction-date-is-invalid","errorCode":null,"errorMessage":"reconstruction date is invalid","messagePattern":"reconstruction date is invalid","errorType":"exception","errorClass":"StarHistoryError","httpStatus":null,"severity":"error","filePath":"scripts/star_history.py","lineNumber":408,"sourceCode":"    daily = reconstruction[\"daily\"]\n    if not isinstance(daily, list):\n        raise StarHistoryError(\"reconstruction.daily must be a list\")\n    if reconstruction_method == \"aggregate_snapshot_only\" and daily:\n        raise StarHistoryError(\"aggregate-only history cannot contain reconstructed dates\")\n\n    previous_day: date | None = None\n    previous_stars = 0\n    for index, raw_point in enumerate(daily):\n        if not isinstance(raw_point, dict):\n            raise StarHistoryError(\"reconstruction point must be an object\")\n        _expect_keys(raw_point, {\"date\", \"stars\"}, \"reconstruction point\")\n        raw_date = raw_point[\"date\"]\n        if not isinstance(raw_date, str):\n            raise StarHistoryError(\"reconstruction date must be a string\")\n        try:\n            point_day = date.fromisoformat(raw_date)\n        except ValueError as exc:\n            raise StarHistoryError(\"reconstruction date is invalid\") from exc\n        if point_day.isoformat() != raw_date:\n            raise StarHistoryError(\"reconstruction date is not canonical\")\n        stars = _strict_non_negative_int(raw_point[\"stars\"], \"reconstruction stars\")\n        if index == 0 and stars <= 0:\n            raise StarHistoryError(\"first reconstruction point must have stars\")\n        if previous_day is not None and point_day <= previous_day:\n            raise StarHistoryError(\"reconstruction dates must be strictly increasing\")\n        if index > 0 and stars <= previous_stars:\n            raise StarHistoryError(\"reconstruction stars must be strictly increasing\")\n        if point_day >= generated_at.date():\n            raise StarHistoryError(\"reconstruction must contain only completed UTC dates\")\n        previous_day = point_day\n        previous_stars = stars\n\n    snapshots = state[\"snapshots\"]\n    if not isinstance(snapshots, list):\n        raise StarHistoryError(\"snapshots must be a list\")\n    previous_snapshot: datetime | None = None","sourceCodeStart":390,"sourceCodeEnd":426,"githubUrl":"https://github.com/666ghj/MiroFish/blob/b5b53acc57189a4a42e44a23e149dc655c98fe82/scripts/star_history.py#L390-L426","documentation":"Raised by validate_state() when a daily point's 'date' string cannot be parsed by date.fromisoformat (ValueError chained as StarHistoryError). This catches syntactically invalid dates before the canonical-form check runs.","triggerScenarios":"validate_state(state) where a date string is e.g. '2024-13-01', '2024-1-1', 'not-a-date', or an ISO datetime like '2024-01-01T00:00:00Z' (fromisoformat on date rejects the time part).","commonSituations":"Writing full timestamps into a date-only field; month/day transposition producing invalid months; string formatting bugs that drop zero padding (caught here or by the canonicality check).","solutions":["Use exactly zero-padded 'YYYY-MM-DD' calendar dates","In producers, always derive the string from date.fromisoformat round-trip or d.isoformat()","If you meant to store a timestamp, it belongs in snapshot.at, not reconstruction daily dates"],"exampleFix":"// before\n{\"date\": \"2024-01-01T00:00:00Z\", \"stars\": 10}\n// after\n{\"date\": \"2024-01-01\", \"stars\": 10}","handlingStrategy":"validation","validationCode":"from datetime import date\nfor p in daily:\n    try:\n        date.fromisoformat(p[\"date\"])\n    except ValueError:\n        raise ValueError(f\"invalid date: {p['date']!r}\")","typeGuard":"from datetime import date\n\ndef are_valid_iso_dates(daily: list) -> bool:\n    try:\n        return all(date.fromisoformat(p[\"date\"]) for p in daily) is not None\n    except (ValueError, TypeError):\n        return False","tryCatchPattern":"try:\n    validate_state(state)\nexcept StarHistoryError as exc:\n    if \"reconstruction date is invalid\" in str(exc):\n        # drop or re-derive bad points, then re-validate\n        ...","preventionTips":["Store calendar dates only ('YYYY-MM-DD'), never timestamps, in daily","Validate dates at ingestion from external sources","Use date.fromisoformat round-trips in tests"],"tags":["validation","date","parsing"],"backgroundTag":null,"analyzedSha":"b5b53acc57189a4a42e44a23e149dc655c98fe82","analyzedAt":"2026-08-14T22:29:33.146Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}