You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The Shields.io GitHub application has been authorized. However, the download badge shows invalid, and it only works for displaying the download count for a single release.
We have a limit on API response, for example, at the default config the limit is 10MB.
I confirmed that that response is larger then 10MB and that's what causes the invalid response as we cancel the request to Github's API once we reach that 10MB limit.
GitHub only expose download count at release asset level. They don't directly expose an aggregate count. The rest API doesn't provide a way to only request certain fields. We have to accept the full release object to get that one field we are interested in. In the case of this particular project, a single release object is very large because every release has hundreds of related assets.
One thing we could possibly look at doing is switching to the v4/GraphQL API (with GithubAuthV4Service). Using that, we might be able to write a query that only requests the ReleaseAsset.downloadCount field. That would return a much smaller response. I haven't tested this, but I think now that GitHub have dropped the max number of objects per page to 100 on the Rest API (even though the code still says per_page=500 GitHub now caps it at 100 objects - see https://docs.github.com/en/rest/releases/releases?apiVersion=2022-11-28#list-releases ) we could request the same number of releases in one query over the GraphQL API as we get back from the rest API. As I say, I have not checked it but worth a look.
In general, the 10Mb limit is there for a reason. It exists to keep performance and memory usage under control. If we have to download and parse >10Mb of data to serve 1 number, that is not a scalable badge. Even if we increased the limit, we probably couldn't serve this badge within camo's 4 second timeout. I am finding that just downloading https://api.github.com/repos/smallprogram/OpenWrtAction/releases?per_page=100 sometimes takes 5 or 6 seconds.
We have a limit on API response, for example, at the default config the limit is 10MB. I confirmed that that response is larger then 10MB and that's what causes the invalid response as we cancel the request to Github's API once we reach that 10MB limit.
I will try to look into that later today.
I think besides the 10MB limit, the problem is here
You can change the logic to paginate requests, 100 per page, until there are no more, and then continue your reduce() operation.
of course this is just my idea
GitHub only expose download count at release asset level. They don't directly expose an aggregate count. The rest API doesn't provide a way to only request certain fields. We have to accept the full release object to get that one field we are interested in. In the case of this particular project, a single release object is very large because every release has hundreds of related assets.
One thing we could possibly look at doing is switching to the v4/GraphQL API (with GithubAuthV4Service). Using that, we might be able to write a query that only requests the ReleaseAsset.downloadCount field. That would return a much smaller response. I haven't tested this, but I think now that GitHub have dropped the max number of objects per page to 100 on the Rest API (even though the code still says per_page=500 GitHub now caps it at 100 objects - see https://docs.github.com/en/rest/releases/releases?apiVersion=2022-11-28#list-releases ) we could request the same number of releases in one query over the GraphQL API as we get back from the rest API. As I say, I have not checked it but worth a look.
In general, the 10Mb limit is there for a reason. It exists to keep performance and memory usage under control. If we have to download and parse >10Mb of data to serve 1 number, that is not a scalable badge. Even if we increased the limit, we probably couldn't serve this badge within camo's 4 second timeout. I am finding that just downloading https://api.github.com/repos/smallprogram/OpenWrtAction/releases?per_page=100 sometimes takes 5 or 6 seconds.
In fact, the slow display speed is not the primary problem, but the error in counting the number of downloads is what needs to be solved urgently.
For performance reasons, we don't write badges that paginate over an unbounded number of responses. We have to be able to return a response quickly.
Ideally, we don't write badges that make more than one upstream request to serve a response. There are a few cases where we make more than one, but it is always a finite number.
That's why we only take into account the most recent N releases for "total" downloads.
Hi @chris48s@jNullj 👋
I'd like to take a stab at fixing this using the GraphQL approach you outlined. Before I start, a couple of quick questions:
For the GraphQL query, I'm planning to request only ReleaseAsset.downloadCount per release — is there a max number of releases per page you'd be comfortable with (e.g. 100)?
Since GitHub GraphQL also caps at 100 nodes per page, repos with more than 100 releases would still require pagination. Should I cap at the first 100 releases (matching the current REST behavior) or is there an acceptable way to handle multiple pages here?
Should this fix cover both the total and per-asset-name cases in transform()?
Happy to proceed with a cap of 100 releases and the GraphQL GithubAuthV4Service pattern once I get the go-ahead!
Following up on the GraphQL suggestion above, I ran some authenticated API experiments on 2026-09-13. I am posting the results here to save future contributors from repeating the same investigation.
TL;DR: requesting only ReleaseAsset.downloadCount greatly reduces the response size for ordinary repositories, and a successful query normally costs only 1 GraphQL point. However, a single 100 releases x 100 assets query is not reliable for the high-asset repositories affected by this issue: GitHub returns RESOURCE_LIMITS_EXCEEDED partial responses or times out before returning data.
Semantics tested
The current REST implementation requests per_page=500, but GitHub caps the endpoint at 100 releases. It nevertheless embeds the complete assets array for each returned release; in practice that can be more than 100 assets per release.
For this experiment I intentionally evaluated the narrower GraphQL semantics discussed above:
GitHub's default first 100 releases, summing only the first 100 assets of each release.
I omitted orderBy deliberately. In a live comparison, releases(first: 100) followed the REST endpoint's default order, while explicitly using CREATED_AT DESC changed the first-page ordering.
Results
Repository/query
Result
photonstorm/phaser, 100 releases
Success: 450 assets, no GraphQL errors, download total matched REST. REST JSON was about 4.45 MB; GraphQL JSON was about 17.5 KB. GraphQL cost was 1 and latency was about 3.6 s.
openai/codex, 10 releases x 100 assets
Success: 804 assets, cost 1, about 3.4 s.
openai/codex, 15 releases x 100 assets
Partial response with 338 RESOURCE_LIMITS_EXCEEDED errors, despite requesting only about 1,300 asset nodes.
openai/codex, 100 releases x 100 assets
Timed out after about 11.7 s without usable data. Its current REST first page contains 15,746 assets across 100 releases, with up to 173 assets in one release.
smallprogram/OpenWrtAction, 31 releases x 100 assets
Returned 3,100 asset nodes but also 2,204 RESOURCE_LIMITS_EXCEEDED errors after about 7.2 s. Its REST response currently contains 5,854 assets, with up to 226 in one release.
Rate-limit and resource observations
A successful query reports rateLimit.cost: 1. This agrees with GitHub's documented primary-cost calculation.
The theoretical maximum here is roughly 10,100 nodes (100 releases plus 10,000 assets), well below GitHub's documented 500,000-node limit.
That node limit is not the binding constraint. GitHub applies additional compute/resource limits which can be reached with far fewer nodes, as the 15-release test shows.
GitHub also terminates GraphQL requests that take longer than about 10 seconds. In one observed timeout, the token's remaining primary allowance fell by roughly 11 points rather than the normal 1; GitHub documents that timed-out queries may incur additional deductions.
Partial data is not sufficient for this service. Shields' BaseGraphqlService rejects a response containing GraphQL errors, and ignoring those errors would produce an incomplete count even under the proposed 100-assets-per-release semantics.
Splitting this into batches of 10 releases appears technically possible, but covering 100 releases would require about 10 upstream requests and roughly 10 primary points per uncached badge response. The observed batches took about 3.4 seconds each, so this also creates substantial latency and secondary-rate-limit/CPU pressure.
Based on these results, GraphQL does not appear to be a suitable direction for this issue. A single query still fails on the high-asset repositories affected here, while batching would introduce too many upstream requests and too much latency.
Activity
jNullj commentedon Jul 18, 2025
We have a limit on API response, for example, at the default config the limit is 10MB.
I confirmed that that response is larger then 10MB and that's what causes the invalid response as we cancel the request to Github's API once we reach that 10MB limit.
I will try to look into that later today.
chris48s commentedon Jul 18, 2025
GitHub only expose download count at release asset level. They don't directly expose an aggregate count. The rest API doesn't provide a way to only request certain fields. We have to accept the full release object to get that one field we are interested in. In the case of this particular project, a single release object is very large because every release has hundreds of related assets.
One thing we could possibly look at doing is switching to the v4/GraphQL API (with
GithubAuthV4Service). Using that, we might be able to write a query that only requests theReleaseAsset.downloadCountfield. That would return a much smaller response. I haven't tested this, but I think now that GitHub have dropped the max number of objects per page to 100 on the Rest API (even though the code still saysper_page=500GitHub now caps it at 100 objects - see https://docs.github.com/en/rest/releases/releases?apiVersion=2022-11-28#list-releases ) we could request the same number of releases in one query over the GraphQL API as we get back from the rest API. As I say, I have not checked it but worth a look.In general, the 10Mb limit is there for a reason. It exists to keep performance and memory usage under control. If we have to download and parse >10Mb of data to serve 1 number, that is not a scalable badge. Even if we increased the limit, we probably couldn't serve this badge within camo's 4 second timeout. I am finding that just downloading https://api.github.com/repos/smallprogram/OpenWrtAction/releases?per_page=100 sometimes takes 5 or 6 seconds.
smallprogram commentedon Jul 18, 2025
I think besides the 10MB limit, the problem is here
shields/services/github/github-downloads.service.js
Lines 118 to 135 in 28f075f
You can change the logic to paginate requests, 100 per page, until there are no more, and then continue your reduce() operation.
of course this is just my idea
smallprogram commentedon Jul 18, 2025
In fact, the slow display speed is not the primary problem, but the error in counting the number of downloads is what needs to be solved urgently.
chris48s commentedon Jul 18, 2025
For performance reasons, we don't write badges that paginate over an unbounded number of responses. We have to be able to return a response quickly.
Ideally, we don't write badges that make more than one upstream request to serve a response. There are a few cases where we make more than one, but it is always a finite number.
That's why we only take into account the most recent N releases for "total" downloads.
smallprogram commentedon Jul 18, 2025
I hope you geniuses can find a better way to solve this problem.
heliocarlitos commentedon Feb 15, 2026
ashif323 commentedon May 5, 2026
Hi @chris48s @jNullj 👋
I'd like to take a stab at fixing this using the GraphQL approach you outlined. Before I start, a couple of quick questions:
For the GraphQL query, I'm planning to request only ReleaseAsset.downloadCount per release — is there a max number of releases per page you'd be comfortable with (e.g. 100)?
Since GitHub GraphQL also caps at 100 nodes per page, repos with more than 100 releases would still require pagination. Should I cap at the first 100 releases (matching the current REST behavior) or is there an acceptable way to handle multiple pages here?
Should this fix cover both the total and per-asset-name cases in transform()?
Happy to proceed with a cap of 100 releases and the GraphQL GithubAuthV4Service pattern once I get the go-ahead!
fix(readme): bust Camo cache and add per-release downloads badge
DCjanus commentedon Aug 29, 2026
The original example no longer reproduces consistently. After checking several repositories, I found a more reliable reproduction case:
invalidThis should provide a stable example for contributors to validate future fixes.
DCjanus commentedon Sep 13, 2026
Following up on the GraphQL suggestion above, I ran some authenticated API experiments on 2026-09-13. I am posting the results here to save future contributors from repeating the same investigation.
TL;DR: requesting only
ReleaseAsset.downloadCountgreatly reduces the response size for ordinary repositories, and a successful query normally costs only 1 GraphQL point. However, a single100 releases x 100 assetsquery is not reliable for the high-asset repositories affected by this issue: GitHub returnsRESOURCE_LIMITS_EXCEEDEDpartial responses or times out before returning data.Semantics tested
The current REST implementation requests
per_page=500, but GitHub caps the endpoint at 100 releases. It nevertheless embeds the completeassetsarray for each returned release; in practice that can be more than 100 assets per release.For this experiment I intentionally evaluated the narrower GraphQL semantics discussed above:
The minimal query was equivalent to:
I omitted
orderBydeliberately. In a live comparison,releases(first: 100)followed the REST endpoint's default order, while explicitly usingCREATED_AT DESCchanged the first-page ordering.Results
photonstorm/phaser, 100 releasesopenai/codex, 10 releases x 100 assetsopenai/codex, 15 releases x 100 assetsRESOURCE_LIMITS_EXCEEDEDerrors, despite requesting only about 1,300 asset nodes.openai/codex, 100 releases x 100 assetssmallprogram/OpenWrtAction, 31 releases x 100 assetsRESOURCE_LIMITS_EXCEEDEDerrors after about 7.2 s. Its REST response currently contains 5,854 assets, with up to 226 in one release.Rate-limit and resource observations
rateLimit.cost: 1. This agrees with GitHub's documented primary-cost calculation.BaseGraphqlServicerejects a response containing GraphQLerrors, and ignoring those errors would produce an incomplete count even under the proposed 100-assets-per-release semantics.Relevant GitHub limits:
per_pagemaximum of 100Based on these results, GraphQL does not appear to be a suitable direction for this issue. A single query still fails on the high-asset repositories affected here, while batching would introduce too many upstream requests and too much latency.