Skip to content

What GitHub will not give

Every entry here was checked against the live API from a personal account, and most of it is not in GitHub’s documentation, which describes what an endpoint should return rather than what it does. It is written down so nobody spends an afternoon finding it out again, and so that a missing panel can be told apart from a broken collector.

Why do two statistics endpoints never answer?

Section titled “Why do two statistics endpoints never answer?”

stats/code_frequency and stats/contributors answer 202 with an empty body, indefinitely, on a personal account. A 202 normally means “still being computed, ask again”, and for these two the next answer is another 202. They are deliberately not called.

The lines added and removed that code_frequency would have given come from the commits collector instead, per commit rather than per week, attributed to an author and dated to the commit. stats/participation and stats/punch_card do work and are used.

Ten seconds is all it takes to see it on your own account:

Terminal window
curl -s -o /dev/null -w '%{http_code}\n' \
-H "Authorization: Bearer $GITHUB_TOKEN" \
https://api.github.com/repos/OWNER/REPO/stats/code_frequency # 202, for ever
curl -s -o /dev/null -w '%{http_code}\n' \
-H "Authorization: Bearer $GITHUB_TOKEN" \
https://api.github.com/repos/OWNER/REPO/stats/participation # 200
EndpointAnswer
/settings/billing/actions410 Gone
/settings/billing/packages410 Gone
/settings/billing/shared-storage410 Gone
/user/settings/billing/usage404
/users/{login}/settings/billing/usageworks

Only the last form works for a personal account, and it returns full RFC 3339 timestamps in a field its documentation describes as a date.

Custom repository properties, classic projects, cost centres and the audit log. A personal account cannot see any of them, however the token is scoped.

  • workflows/{id}/timing returns 200 with an always-empty billable object. It looks like the source for per-workflow minutes and is not.
  • The stargazer list, to anyone but the repository’s admins and collaborators. Since July 2026 GitHub serves it to no one else. REST answers 404, and GraphQL’s stargazers answers an empty list with a totalCount of 0 while stargazerCount beside it still gives the real number: measured on cli/cli and octocat/Hello-World with a token holding every scope. ghchronicle therefore writes gh_star, who starred and when to the second, only where the token has that access, which it always has on the account’s own repositories and on those of an organisation the account administers; one named in targets.repos or reached through targets.orgs without it has its stars counted per day from the history below, and nobody named.
  • /user/installations returns 403 without a GitHub App.

The star history github.com serves to anyone

Section titled “The star history github.com serves to anyone”

stargazers/history answers where the stargazer list does not. It serves anyone who can see the repository, unauthenticated too: the stars given per day, grouped by week, thirty weeks to a page, which is both the default and the most per_page allows (a smaller one is honoured, a larger one is cut to thirty), paging back to the repository’s first week (measured on cli/cli: thirteen pages, back to 2019). It names no stargazers, so it cannot stand in for gh_star, which is one row per star at the instant it was given and says who gave it. It can stand in for the count, and ghchronicle reads it for every repository it collects, writes it as gh_star_day and draws from it the panels that count stars by day in every store but Prometheus, which cannot hold a history and still counts gh_star.

Three things about it were measured rather than read in its documentation. The days are GitHub’s calendar days in America/Los_Angeles, under a week labelled as Sunday 00:00 UTC: against the stargazer lists of nineteen repositories, the Pacific day matched all 440 stars and the UTC day did not. It counts the repository’s current stargazers, each on the day they starred, so an unstar takes a star off a day in the past rather than the day it happened. And a 304 answer to it carries no Link header, where a 200 carries next and last, so the walk reads no Link at all and stops at a page shorter than thirty weeks or an empty one.

GraphQL reports zero packages for an account while REST lists them. The pretty query is simply wrong here, so packages come from REST, at one call per package for its versions.

A repository with no traffic does not return an empty window. GitHub keeps returning the last fourteen days that had data, so the window can end weeks ago. The collector records what it is told.

None of the above is treated as a failure. ghapi.UnavailableError (403 or 404: the feature is switched off) and ghapi.NotReadyError (202: GitHub is still computing) both mean “there is nothing here”, and the sweep continues to the next repository. The activity feeds have their own version of this: past their ceiling GitHub answers 422 “pagination is limited for this resource”, which is read as the end of the data rather than as an error.

  • Rate limits is the other half of this: what the calls that do work cost, and why a 304 costs nothing.
  • Cost of a sweep prices every family.
Written and maintained by
MIT licenceRelease history