666ghj/MiroFish · error · StarHistoryError
reconstruction date is invalid
Error message
reconstruction date is invalid
What it means
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.
Source
Thrown at scripts/star_history.py:408
daily = reconstruction["daily"]
if not isinstance(daily, list):
raise StarHistoryError("reconstruction.daily must be a list")
if reconstruction_method == "aggregate_snapshot_only" and daily:
raise StarHistoryError("aggregate-only history cannot contain reconstructed dates")
previous_day: date | None = None
previous_stars = 0
for index, raw_point in enumerate(daily):
if not isinstance(raw_point, dict):
raise StarHistoryError("reconstruction point must be an object")
_expect_keys(raw_point, {"date", "stars"}, "reconstruction point")
raw_date = raw_point["date"]
if not isinstance(raw_date, str):
raise StarHistoryError("reconstruction date must be a string")
try:
point_day = date.fromisoformat(raw_date)
except ValueError as exc:
raise StarHistoryError("reconstruction date is invalid") from exc
if point_day.isoformat() != raw_date:
raise StarHistoryError("reconstruction date is not canonical")
stars = _strict_non_negative_int(raw_point["stars"], "reconstruction stars")
if index == 0 and stars <= 0:
raise StarHistoryError("first reconstruction point must have stars")
if previous_day is not None and point_day <= previous_day:
raise StarHistoryError("reconstruction dates must be strictly increasing")
if index > 0 and stars <= previous_stars:
raise StarHistoryError("reconstruction stars must be strictly increasing")
if point_day >= generated_at.date():
raise StarHistoryError("reconstruction must contain only completed UTC dates")
previous_day = point_day
previous_stars = stars
snapshots = state["snapshots"]
if not isinstance(snapshots, list):
raise StarHistoryError("snapshots must be a list")
previous_snapshot: datetime | None = NoneView on GitHub (pinned to b5b53acc57)
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
Example fix
// before
{"date": "2024-01-01T00:00:00Z", "stars": 10}
// after
{"date": "2024-01-01", "stars": 10} Defensive patterns
Strategy: validation
Validate before calling
from datetime import date
for p in daily:
try:
date.fromisoformat(p["date"])
except ValueError:
raise ValueError(f"invalid date: {p['date']!r}") Type guard
from datetime import date
def are_valid_iso_dates(daily: list) -> bool:
try:
return all(date.fromisoformat(p["date"]) for p in daily) is not None
except (ValueError, TypeError):
return False Try / catch
try:
validate_state(state)
except StarHistoryError as exc:
if "reconstruction date is invalid" in str(exc):
# drop or re-derive bad points, then re-validate
... Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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).
Related errors
- GitHub GraphQL edges were not a list
- GitHub GraphQL returned an invalid edge
- GitHub GraphQL returned an invalid star timestamp
- GitHub returned an invalid star timestamp
- reconstruction date must be a string
AI-assisted analysis of 666ghj/MiroFish@b5b53acc57 (2026-08-14).
Data as JSON: /api/errors/f35c5e300ea46d62.
Report an issue: GitHub.