666ghj/MiroFish · error · StarHistoryError

history interval must be exactly {INTERVAL_DAYS} days

Error message

history interval must be exactly {INTERVAL_DAYS} days

What it means

validate_state requires ongoing_interval_days to equal the module constant INTERVAL_DAYS (13) and be a real int; a mismatch raises StarHistoryError(f'history interval must be exactly {INTERVAL_DAYS} days'). The interval defines the ongoing-snapshot cadence baked into the stored data, so changing it without rebuilding state would corrupt the timeline.

Source

Thrown at scripts/star_history.py:369

            "repository",
            "timezone",
            "ongoing_interval_days",
            "reconstruction",
            "snapshots",
        },
        "history state",
    )
    if state["schema_version"] != 1 or type(state["schema_version"]) is not int:
        raise StarHistoryError("unsupported history schema_version")
    if state["repository"] != REPOSITORY:
        raise StarHistoryError("history repository does not match configured repository")
    if state["timezone"] != "UTC":
        raise StarHistoryError("history timezone must be UTC")
    if (
        state["ongoing_interval_days"] != INTERVAL_DAYS
        or type(state["ongoing_interval_days"]) is not int
    ):
        raise StarHistoryError(
            f"history interval must be exactly {INTERVAL_DAYS} days"
        )

    reconstruction = state["reconstruction"]
    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(

View on GitHub (pinned to b5b53acc57)

Solutions

  1. Revert INTERVAL_DAYS to 13 if you want to keep the existing state
  2. Or delete the state file and rebuild history after changing the interval — stored snapshots assume the old cadence and cannot be reused
  3. Never edit ongoing_interval_days in the JSON by hand to match new code; the data would still be inconsistent

Example fix

# before (scripts/star_history.py)
INTERVAL_DAYS = 13
# changed to:
INTERVAL_DAYS = 7  # but state still says 13

# after
INTERVAL_DAYS = 7
rm state.json && python scripts/star_history.py  # full rebuild under the new cadence
Defensive patterns

Strategy: validation

Validate before calling

interval = state.get("ongoing_interval_days")
if type(interval) is not int or interval != INTERVAL_DAYS:
    raise StarHistoryError(f"state interval {interval!r} != configured {INTERVAL_DAYS}; rebuild the state")

Type guard

def state_interval_matches(state: object) -> TypeGuard[dict]:
    return (
        isinstance(state, dict)
        and type(state.get("ongoing_interval_days")) is int
        and state["ongoing_interval_days"] == INTERVAL_DAYS
    )

Try / catch

try:
    validate_state(state)
except StarHistoryError as exc:
    if "history interval" in str(exc):
        regenerate_state_file()  # cadence changed; old snapshots are unusable
    else:
        raise

Prevention

When it happens

Trigger: A state file with ongoing_interval_days: 7 or 30 (written when INTERVAL_DAYS had a different value), a float like 13.0, or editing INTERVAL_DAYS in source while keeping old state.

Common situations: Tuning INTERVAL_DAYS in scripts/star_history.py (currently 13) and reusing an existing state file; merging state from a fork with a different cadence.

Related errors


AI-assisted analysis of 666ghj/MiroFish@b5b53acc57 (2026-08-14). Data as JSON: /api/errors/3624839803625942. Report an issue: GitHub.