666ghj/MiroFish · error · StarHistoryError
reconstruction date must be a string
Error message
reconstruction date must be a string
What it means
Raised by validate_state() when a daily point's 'date' field is not a Python str (JSON string). The date must be an ISO-format string that is subsequently parsed with date.fromisoformat, so non-string types fail before parsing is attempted.
Source
Thrown at scripts/star_history.py:404
raise StarHistoryError("unsupported reconstruction method")
generated_at = _parse_state_timestamp(
reconstruction["generated_at"], "reconstruction.generated_at"
)
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
View on GitHub (pinned to b5b53acc57)
Solutions
- Emit dates as strings in 'YYYY-MM-DD' form
- When generating state in Python, use point_day.isoformat() rather than str/int conversions
- Regenerate state rather than patching individual fields by hand
Example fix
// before
{"date": 20240101, "stars": 10}
// after
{"date": "2024-01-01", "stars": 10} Defensive patterns
Strategy: type-guard
Validate before calling
for p in state["reconstruction"]["daily"]:
if not isinstance(p["date"], str):
p["date"] = p["date"].isoformat() if hasattr(p["date"], "isoformat") else str(p["date"]) Type guard
def has_string_dates(daily: list) -> bool:
return all(isinstance(p.get("date"), str) for p in daily) Try / catch
try:
validate_state(state)
except StarHistoryError as exc:
if "reconstruction date must be a string" in str(exc):
# coerce date objects to ISO strings, then re-validate
... Prevention
- Always call .isoformat() on date objects when writing JSON
- Never rely on implicit str(date) formatting differing from ISO
- Type-check producer payloads before serialization
When it happens
Trigger: validate_state(state) where a daily point has date: 20240101 (number), date: null, or date: {"year": 2024, ...}.
Common situations: Programmatic generation where a datetime.date object was serialized incorrectly or an int-encoded date was used to save space; hand-edited files.
Related errors
- {label} must use YYYY-MM-DDTHH:MM:SSZ
- {label} is not a valid UTC timestamp
- {label} contains missing or unknown fields
- history state must be a JSON object
- unsupported history schema_version
AI-assisted analysis of 666ghj/MiroFish@b5b53acc57 (2026-08-14).
Data as JSON: /api/errors/7ce5eff5f26712f3.
Report an issue: GitHub.