666ghj/MiroFish · error · StarHistoryError
{label} must be a non-negative integer
Error message
{label} must be a non-negative integer What it means
The helper _strict_non_negative_int rejected a value that was not exactly an int (type(value) is not int — bools and floats fail) or was negative. It is used for stargazers.totalCount and rateLimit.remaining, raising StarHistoryError(f'{label} must be a non-negative integer') with the caller-supplied label such as 'GraphQL totalCount'.
Source
Thrown at scripts/star_history.py:303
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
def _parse_github_timestamp(value: str) -> datetime:
try:
parsed = datetime.fromisoformat(value.replace("Z", "+00:00"))
except ValueError as exc:
raise StarHistoryError("GitHub returned an invalid star timestamp") from exc
if parsed.tzinfo is None or parsed.utcoffset() != timedelta(0):
raise StarHistoryError("GitHub star timestamp was not UTC")
return parsed.astimezone(UTC)
def _parse_state_timestamp(value: Any, label: str) -> datetime:
if not isinstance(value, str) or not STATE_TIMESTAMP_RE.fullmatch(value):
raise StarHistoryError(f"{label} must use YYYY-MM-DDTHH:MM:SSZ")
try:
parsed = datetime.strptime(value, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=UTC)View on GitHub (pinned to b5b53acc57)
Solutions
- Ensure the query selects totalCount on stargazers and rateLimit { remaining } at the top level
- Check the error's label to see which field failed, then inspect that field in the raw response
- Fix fixtures to use plain non-negative ints (not floats or numeric strings)
Example fix
// before (query fragment)
query($after: String) { rateLimit { cost } }
// after (query fragment)
query($after: String) { rateLimit { remaining } } Defensive patterns
Strategy: validation
Validate before calling
for label, value in (("totalCount", sg.get("totalCount")), ("rate remaining", rl.get("remaining"))):
if type(value) is not int or value < 0:
raise StarHistoryError(f"{label} must be a non-negative integer") Type guard
def is_strict_non_negative_int(value: object) -> TypeGuard[int]:
return type(value) is int and value >= 0 Try / catch
try:
total = _strict_non_negative_int(sg.get("totalCount"), "GraphQL totalCount")
except StarHistoryError as exc:
raise StarHistoryError("query must select stargazers.totalCount as an int") from exc Prevention
- Always select totalCount and rateLimit { remaining } in the query
- Remember bool is an int subclass but type() checks reject it — use real ints in fixtures
When it happens
Trigger: totalCount: null when the totalCount field was not selected in the query; rateLimit.remaining as a float or string from a proxy; a negative or missing rateLimit block (e.g. query edited to drop rateLimit).
Common situations: Editing the GraphQL query and forgetting totalCount or rateLimit { remaining } in the selection; fixtures using floats; GitHub returning rateLimit: null when the query omits it.
Related errors
- GitHub GraphQL edges were not a list
- GitHub GraphQL returned an invalid edge
- GitHub GraphQL returned an invalid edge cursor
- GitHub GraphQL returned an invalid star timestamp
- GitHub GraphQL returned invalid page information
AI-assisted analysis of 666ghj/MiroFish@b5b53acc57 (2026-08-14).
Data as JSON: /api/errors/8b2e9e17f2e1336a.
Report an issue: GitHub.