666ghj/MiroFish · error · StarHistoryError
GitHub GraphQL returned an invalid page cursor
Error message
GitHub GraphQL returned an invalid page cursor
What it means
pageInfo.endCursor was present but not a string (None is allowed and handled separately — the failure is for numbers, dicts, lists, bools). endCursor is the opaque pagination token for the next request, so the parser raises StarHistoryError('GitHub GraphQL returned an invalid page cursor') when it cannot be used as one.
Source
Thrown at scripts/star_history.py:288
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,
rate_remaining=rate_remaining,
)
def _strict_non_negative_int(value: Any, label: str) -> int:
if type(value) is not int or value < 0:
raise StarHistoryError(f"{label} must be a non-negative integer")
return value
View on GitHub (pinned to b5b53acc57)
Solutions
- Fix the fixture/mock to return endCursor as a string or null
- Log the raw end_cursor value to identify its actual type
- Re-run against the real GitHub endpoint to confirm it is a stub-only issue
Example fix
// before (fixture) "endCursor": 42 // after (fixture) "endCursor": "42"
Defensive patterns
Strategy: validation
Validate before calling
end_cursor = page_info.get("endCursor", "missing")
if end_cursor != "missing" and end_cursor is not None and not isinstance(end_cursor, str):
raise StarHistoryError("endCursor is not a string") Type guard
def end_cursor_ok(value: object) -> bool:
return value is None or isinstance(value, str) Try / catch
try:
page = _parse_graphql_page(payload)
except StarHistoryError as exc:
if "invalid page cursor" in str(exc):
raise StarHistoryError("pagination token unusable; refusing to continue") from exc
raise Prevention
- Keep endCursor as a string in all fixtures and stubs; null means 'no more pages'
- Never coerce cursors between types — they are opaque tokens
When it happens
Trigger: endCursor: 12345, an object, or a list in the response — typically from a fixture or a modified/stubbed GraphQL endpoint, since real GitHub always returns a string or null.
Common situations: Hand-built fixtures where endCursor was an integer cursor index; a mock server returning {'endCursor': {'value': 'x'}}.
Related errors
- GitHub GraphQL returned an invalid edge cursor
- GitHub GraphQL returned invalid page information
- GitHub GraphQL omitted the next page cursor
- GitHub returned an invalid pagination cursor
- GitHub GraphQL edges were not a list
AI-assisted analysis of 666ghj/MiroFish@b5b53acc57 (2026-08-14).
Data as JSON: /api/errors/d02a9e12e2a5d0eb.
Report an issue: GitHub.