666ghj/MiroFish · error · StarHistoryError

stargazer list changed or was incomplete during backfill

Error message

stargazer list changed or was incomplete during backfill

What it means

Raised at scripts/star_history.py:609 after the backfill completes. The script compares `len(seen_edge_cursors)` against the `totalCount` reported by the very first page (`initial_total`); a mismatch means the pages traversed did not cover exactly the stargazer set GitHub advertised, so the per-day star counts in `daily_increments` would be wrong (under- or over-counted). The state file is therefore not written.

Source

Thrown at scripts/star_history.py:609

            if edge.starred_at.date() < normalized_now.date():
                daily_increments[edge.starred_at.date()] += 1

        if page.end_cursor is not None:
            if page.end_cursor in seen_page_cursors:
                raise StarHistoryError("GitHub GraphQL repeated a page cursor")
            seen_page_cursors.add(page.end_cursor)
        if not page.has_next_page:
            break
        if page.end_cursor is None:
            raise StarHistoryError("GitHub GraphQL omitted the next page cursor")
        after = page.end_cursor
        if page_number > 10_000:
            raise StarHistoryError("GitHub GraphQL exceeded the page safety limit")

    if initial_total is None:
        raise StarHistoryError("GitHub GraphQL returned no pages")
    if len(seen_edge_cursors) != initial_total:
        raise StarHistoryError("stargazer list changed or was incomplete during backfill")

    running = 0
    daily: list[dict[str, Any]] = []
    for point_day in sorted(daily_increments):
        running += daily_increments[point_day]
        daily.append({"date": point_day.isoformat(), "stars": running})

    state: dict[str, Any] = {
        "schema_version": 1,
        "repository": REPOSITORY,
        "timezone": "UTC",
        "ongoing_interval_days": INTERVAL_DAYS,
        "reconstruction": {
            "method": "current_stargazers_starred_at",
            "generated_at": _format_state_timestamp(normalized_now),
            "daily": daily,
        },
        "snapshots": [],

View on GitHub (pinned to b5b53acc57)

Solutions

  1. Re-run the backfill at a quieter time — churn-induced mismatch is by far the most common cause and a retry usually converges.
  2. If it persists on a busy repo, retry a few times; small mismatches (±1–2) resolve as churn settles, and the check guarantees you never persist a wrong history.
  3. In test doubles, make `total_count` exactly equal the total number of distinct edges the fake will return across all pages.
  4. For very large repos, verify the star count with `gh api repos/{owner}/{repo} --jq .stargazers_count` before and after the run to confirm whether real churn explains the delta.

Example fix

# test double: total_count must match the sum of edges over all pages
TOTAL = 500
# before: StargazerPage(total_count=999, ...)
# after:
return StargazerPage(
    total_count=TOTAL,
    edges=all_edges[page_index * 100:(page_index + 1) * 100],
    has_next_page=(page_index + 1) * 100 < TOTAL,
    end_cursor=f"page-{page_index}" if (page_index + 1) * 100 < TOTAL else None,
    rate_remaining=5000,
)
Defensive patterns

Strategy: retry

Try / catch

for attempt in range(3):
    try:
        state = run_backfill(gateway, clock)
        break
    except StarHistoryError as exc:
        if "changed or was incomplete" not in str(exc) or attempt == 2:
            raise
        logger.info("stargazer churn during backfill (attempt %d); retrying", attempt + 1)

Prevention

When it happens

Trigger: Stars added or removed between the first page fetch (which fixes `initial_total`) and the last page: every new star means an extra edge collected (len > total), every un-star means one missing (len < total). Also fires when GitHub's `totalCount` is eventually consistent with the edge stream on huge repositories.

Common situations: Backfilling an actively starred repository (e.g. trending on GitHub) where churn during a multi-minute pagination run is guaranteed; running the one-time maintainer backfill right after a publicity event; test gateways whose `total_count` field disagrees with the number of edges they emit across all pages.

Related errors


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