666ghj/MiroFish · error · StarHistoryError
reconstruction.daily must be a list
Error message
reconstruction.daily must be a list
What it means
Raised by validate_state() when reconstruction['daily'] is not a JSON array. 'daily' holds the reconstructed per-day star count points, each an object with 'date' and 'stars'; anything other than a list (dict, string, number, null) fails immediately before per-point validation.
Source
Thrown at scripts/star_history.py:392
if not isinstance(reconstruction, dict):
raise StarHistoryError("reconstruction must be an object")
_expect_keys(
reconstruction,
{"method", "generated_at", "daily"},
"reconstruction",
)
reconstruction_method = reconstruction["method"]
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")View on GitHub (pinned to b5b53acc57)
Solutions
- Make daily a JSON array of {"date": "YYYY-MM-DD", "stars": <int>} objects (it may be empty for aggregate_snapshot_only)
- If using a date-keyed map internally, convert it to a list sorted by date before writing state
- Regenerate the state with the current script rather than hand-transforming it
Example fix
// before
"daily": {"2024-01-01": 10, "2024-01-02": 25}
// after
"daily": [{"date": "2024-01-01", "stars": 10}, {"date": "2024-01-02", "stars": 25}] Defensive patterns
Strategy: type-guard
Validate before calling
if not isinstance(state["reconstruction"].get("daily"), list):
daily = [] if state["reconstruction"].get("daily") is None else sorted(
[{"date": d, "stars": s} for d, s in state["reconstruction"]["daily"].items()],
key=lambda p: p["date"],
) Type guard
def is_daily_list(value) -> bool:
return isinstance(value, list) and all(
isinstance(p, dict) and set(p) == {"date", "stars"} for p in value
) Try / catch
try:
validate_state(state)
except StarHistoryError as exc:
if "reconstruction.daily must be a list" in str(exc):
# normalize a date-keyed map to a sorted list, then re-validate
... Prevention
- Serialize daily as a sorted array, never a date-keyed object
- Run validate_state in CI on any committed state file
- Keep one canonical serializer for the state document
When it happens
Trigger: validate_state(state) where reconstruction.daily is an object keyed by date (e.g. {"2024-01-01": 10}) instead of a list of points, or a null/string value from a partial hand edit.
Common situations: Converting the daily data to a date-keyed map for convenience and forgetting to convert back; merging state files with a tool that changed the array to an object; older producers that emitted a different structure.
Related errors
- history state must be a JSON object
- reconstruction must be an object
- reconstruction point must be an object
- 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/24a992f28bc5877b.
Report an issue: GitHub.