666ghj/MiroFish · error · StarHistoryError

GitHub GraphQL returned an invalid edge cursor

Error message

GitHub GraphQL returned an invalid edge cursor

What it means

An edge object lacked a usable cursor: cursor was not a str, or was an empty string. Cursors are mandatory for cursor-based pagination of stargazers (they are passed as the $after variable for the next page), so the parser raises StarHistoryError('GitHub GraphQL returned an invalid edge cursor') rather than attempting to continue from a missing position.

Source

Thrown at scripts/star_history.py:278

            raise StarHistoryError("GitHub GraphQL response had an unexpected shape")

        total_count = _strict_non_negative_int(
            stargazers.get("totalCount"), "GraphQL totalCount"
        )
        rate_remaining = _strict_non_negative_int(
            rate_limit.get("remaining"), "GraphQL rate remaining"
        )
        if not isinstance(raw_edges, list):
            raise StarHistoryError("GitHub GraphQL edges were not a list")

        edges: list[StargazerEdge] = []
        for raw_edge in raw_edges:
            if not isinstance(raw_edge, dict):
                raise StarHistoryError("GitHub GraphQL returned an invalid edge")
            cursor = raw_edge.get("cursor")
            starred_at = raw_edge.get("starredAt")
            if not isinstance(cursor, str) or not cursor:
                raise StarHistoryError("GitHub GraphQL returned an invalid edge cursor")
            if not isinstance(starred_at, str):
                raise StarHistoryError("GitHub GraphQL returned an invalid star timestamp")
            edges.append(StargazerEdge(cursor, _parse_github_timestamp(starred_at)))

        has_next_page = page_info.get("hasNextPage")
        end_cursor = page_info.get("endCursor")
        if type(has_next_page) is not bool:
            raise StarHistoryError("GitHub GraphQL returned invalid page information")
        if end_cursor is not None and not isinstance(end_cursor, str):
            raise StarHistoryError("GitHub GraphQL returned an invalid page cursor")
        if has_next_page and not end_cursor:
            raise StarHistoryError("GitHub GraphQL omitted the next page cursor")

        return StargazerPage(
            total_count=total_count,
            edges=tuple(edges),
            has_next_page=has_next_page,
            end_cursor=end_cursor,

View on GitHub (pinned to b5b53acc57)

Solutions

  1. Restore `cursor` in the edges selection of the GraphQL query if it was removed
  2. Fix test fixtures so every edge has a non-empty string cursor
  3. Log the failing edge to distinguish null vs empty string — null means the field was not selected, empty means malformed data

Example fix

// before (query fragment)
edges { node { ... } }

// after (query fragment)
edges { cursor starredAt }
Defensive patterns

Strategy: validation

Validate before calling

for edge in raw_edges:
    if not isinstance(edge, dict) or not isinstance(edge.get("cursor"), str) or not edge["cursor"]:
        raise StarHistoryError("edge without usable cursor; cannot paginate safely")
        break

Type guard

def has_usable_cursor(edge: object) -> TypeGuard[dict]:
    return isinstance(edge, dict) and isinstance(edge.get("cursor"), str) and bool(edge["cursor"])

Try / catch

try:
    page = _parse_graphql_page(payload)
except StarHistoryError as exc:
    if "invalid edge cursor" in str(exc):
        raise StarHistoryError("pagination aborted: GitHub omitted a cursor — restart collection from last good cursor") from exc
    raise

Prevention

When it happens

Trigger: An edge with cursor: null (cursor field not selected in the query, or GitHub omitted it), cursor: 123, or cursor: "". Also happens if the query was edited to drop the cursor selection while the parser still expects it.

Common situations: Hand-modified GraphQL query that removed `cursor` from the edges selection; test fixtures copying edges without cursors; GitHub API behavior change.

Related errors


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