666ghj/MiroFish · error · StarHistoryError

GitHub GraphQL exceeded the page safety limit

Error message

GitHub GraphQL exceeded the page safety limit

What it means

Raised at scripts/star_history.py:604 after `page_number` exceeds 10,000 in the backfill `while True` loop. With PAGE_SIZE=100 this caps a single backfill at 1,000,000 stargazers. It is a deliberate safety limit so a cursor bug (see the repeated-cursor guards) cannot turn into an unbounded, rate-limit-burning fetch loop.

Source

Thrown at scripts/star_history.py:604

                raise StarHistoryError("insufficient GitHub GraphQL rate limit for backfill")
        for edge in page.edges:
            if edge.cursor in seen_edge_cursors:
                raise StarHistoryError("GitHub GraphQL repeated an edge cursor")
            seen_edge_cursors.add(edge.cursor)
            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": {

View on GitHub (pinned to b5b53acc57)

Solutions

  1. Confirm the repository actually has ~1M+ stargazers via `gh api repos/{owner}/{repo}`; if it does, the backfill design does not support it — raise the safety limit in a fork or backfill in chunks by date.
  2. If the star count is far below 1M, the loop is not terminating: check that the gateway's `has_next_page` eventually becomes False and that `end_cursor` advances (see the repeated/omitted-cursor errors).
  3. Re-run during a quiet window so concurrent churn cannot extend pagination indefinitely.
  4. Inspect logs for how many distinct edge cursors were collected versus `initial_total` to distinguish a genuine huge repo from a looping traversal.
Defensive patterns

Strategy: try-catch

Validate before calling

# Before the backfill, check the repo size against the hard cap
import subprocess, json
info = json.loads(subprocess.run(
    ["gh", "api", "repos/666ghj/MiroFish"], capture_output=True, text=True, check=True
).stdout)
if info["stargazers_count"] > 10_000 * 100:  # pages safety limit * PAGE_SIZE
    raise SystemExit("repository exceeds backfill page safety limit; backfill unsupported")

Try / catch

try:
    state = run_backfill(gateway, clock)
except StarHistoryError as exc:
    if "page safety limit" in str(exc):
        raise SystemExit(
            "backfill exceeded 10,000 pages (≈1M stars) or pagination never terminated"
        ) from exc
    raise

Prevention

When it happens

Trigger: Calling the stargazer backfill on a repository whose `totalCount` implies more than 10,000 pages (stars > 1,000,000), or a pagination malfunction that keeps yielding new-but-non-terminating pages so `page_number` keeps climbing past 10,000 without `has_next_page` ever becoming false.

Common situations: Extremely popular repositories (1M+ stars — beyond every real repo today, so in practice this fires only in tests or when pagination is malfunctioning); synthetic test states with huge `total_count`; a fake gateway that always says has_next_page=True with fresh cursors.

Related errors


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