666ghj/MiroFish · error · StarHistoryError
reconstruction point must be an object
Error message
reconstruction point must be an object
What it means
Raised by validate_state() while iterating reconstruction.daily when an element is not a JSON object. Each daily point must be a dict with exactly the keys 'date' and 'stars' (enforced next by _expect_keys); arrays, strings, numbers, or nulls fail here.
Source
Thrown at scripts/star_history.py:400
if reconstruction_method not in {
"current_stargazers_starred_at",
"aggregate_snapshot_only",
}:
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():View on GitHub (pinned to b5b53acc57)
Solutions
- Make every daily element an object {"date": ..., "stars": ...} with exactly those two keys
- Remove any extra fields — _expect_keys rejects unknown as well as missing fields
- Regenerate the state with the canonical writer (canonical_state_bytes)
Example fix
// before
"daily": [["2024-01-01", 10]]
// after
"daily": [{"date": "2024-01-01", "stars": 10}] Defensive patterns
Strategy: type-guard
Validate before calling
daily = state["reconstruction"]["daily"]
if not all(isinstance(p, dict) for p in daily):
daily = [{"date": p[0], "stars": p[1]} if isinstance(p, (list, tuple)) else p for p in daily] Type guard
def are_daily_points_objects(daily: list) -> bool:
return all(isinstance(p, dict) and set(p) == {"date", "stars"} for p in daily) Try / catch
try:
validate_state(state)
except StarHistoryError as exc:
if "reconstruction point must be an object" in str(exc):
# locate the offending index via enumerate and re-serialize that point
... Prevention
- Use json.dumps on dicts, not on tuples, when producing state
- Validate producer output with validate_state before persisting
- Keep daily elements structurally uniform
When it happens
Trigger: validate_state(state) where a daily entry is e.g. ["2024-01-01", 10] (tuple-style array) or a bare integer star count.
Common situations: Producing state from a different language/serializer that emitted arrays instead of objects; hand-editing the daily list; a partially applied data transform.
Related errors
- history state must be a JSON object
- reconstruction must be an object
- reconstruction.daily must be a list
- snapshots must be a list
- snapshot must be an object
AI-assisted analysis of 666ghj/MiroFish@b5b53acc57 (2026-08-14).
Data as JSON: /api/errors/ea2804615e957c49.
Report an issue: GitHub.