Repository navigation
[Bug]: v3.0.2 release lookup can time out on repositories with large release metadata #829
Description
Pre-flight checks
- I searched existing issues and did not find a duplicate
- I reproduced this with the latest released version or current
master - I included a reproducible example or a sanitized/redacted reproduction path if the original repository is private
action-gh-release version
v3.0.2 (softprops/action-gh-release@v3, resolving to 3d0d9888cb7fd7b750713d6e236d1fcb99157228 at the time of the failures)
Runner operating system
ubuntu-latest
Release target repository
sagemath/sage
Reproduction repo, gist, or artifact
- Latest failing job: https://github.com/sagemath/sage/actions/runs/30219480939/job/89840469383
- Earlier failure with the same annotation: https://github.com/sagemath/sage/actions/runs/29456228906/job/87491951057
- Last successful release before v3.0.2: https://github.com/sagemath/sage/actions/runs/28750105111
Workflow snippet
- name: Create release
uses: softprops/action-gh-release@v3
with:
preserve_order: true
files: |
dist/*
upstream/*
token: ${{ secrets.RELEASE_CREATION_TOKEN }}
body_path: release_notes
prerelease: ${{ contains(github.ref_name, 'beta') || contains(github.ref_name, 'rc') }}
max_retries: 3max_retries is not a declared action input, so the warning about that input is understood and is not being reported as the cause. The workflow has since removed it.
Expected behavior
When the tag does not have a release yet, the action should create the release and upload the selected assets. A repository with many release assets should not make the missing-tag lookup time out.
Actual behavior
The Create release step fails before creating the release. In the latest run it ran for about 11 seconds (2026-07-26 20:54:40Z to 20:54:51Z), after all preceding jobs and artifact downloads had succeeded.
The public check annotation is:
We couldn't respond to your request in time. Sorry about that. Please try resubmitting your request and contact us if the problem persists.
The same workflow succeeded for 10.10.beta5 while @v3 resolved to v3.0.1, then failed for 10.10.beta6 and 10.10.beta7 after v3.0.2 was released. Pinning both Sage call sites to v3.0.1 is the current workaround: sagemath/sage#42599
Steps to reproduce
- Use v3.0.2 in a repository whose release-list response contains a large amount of embedded asset metadata, such as the public
sagemath/sagerepository. - Trigger the action for a new tag that does not yet have a GitHub release.
- The direct
getReleaseByTagrequest returns 404, after which v3.0.2 callsrecentReleasesByTag. recentReleasesByTagscans up to two pages throughallReleases, which fixesper_page: 100.- The first release-list request can time out before release creation begins.
The API payload characteristic can be reproduced without modifying anything:
curl -sS -o /dev/null -w 'status=%{http_code} bytes=%{size_download} time=%{time_total}s\n' \
'https://api.github.com/repos/sagemath/sage/releases?per_page=100&page=1'Measured on 2026-07-30:
status=200 bytes=36612072 time=20.220455s
For comparison, a direct lookup of a nonexistent tag returned a 147-byte 404 in 0.96 seconds.
Relevant logs
Warning: Unexpected input(s) 'max_retries'
Error: We couldn't respond to your request in time. Sorry about that. Please try resubmitting your request and contact us if the problem persists.
The raw job log is not publicly downloadable without repository administration rights, so the exact timed-out HTTP route is inferred rather than proven from the log. The public annotation, v3.0.1/v3.0.2 boundary, and endpoint measurements strongly point to the new release-list fallback.
Additional context
PR #801 introduced the fallback scan so draft releases can still be found after the direct tag lookup returns 404: #801
Current master (5a6f51711ce2ba103b78f5e9550f810679f11e0e) retains the same path:
allReleasessetsper_page: 100:action-gh-release/src/github.ts
Lines 290 to 295 in 5a6f517
allReleases(params: { owner: string; repo: string }): AsyncIterable<{ data: Release[] }> { const updatedParams = { per_page: 100, ...params }; return this.github.paginate.iterator( this.github.rest.repos.listReleases.endpoint.merge(updatedParams), ); } - the 404 fallback calls
recentReleasesByTag:action-gh-release/src/github.ts
Lines 865 to 924 in 5a6f517
export async function findTagFromReleases( releaser: Releaser, owner: string, repo: string, tag: string, listingAttempts: number = 1, ): Promise<Release | undefined> { try { const { data: release } = await releaser.getReleaseByTag({ owner, repo, tag }); return release; } catch (error) { if (getErrorStatus(error) !== 404) { throw error; } } if (listingAttempts <= 0) { return undefined; } const attempts = Math.max(1, listingAttempts); for (let attempt = 0; attempt < attempts; attempt += 1) { const recentReleases = await recentReleasesByTag(releaser, owner, repo, tag); const canonicalRelease = pickCanonicalRelease(recentReleases, undefined); if (canonicalRelease) { return canonicalRelease; } if (attempt < attempts - 1) { await sleep(CREATED_RELEASE_DISCOVERY_RETRY_DELAY_MS); } } return undefined; } const CREATED_RELEASE_DISCOVERY_RETRY_DELAY_MS = 1000; const RECENT_RELEASE_SCAN_PAGES = 2; async function sleep(ms: number): Promise<void> { await new Promise((resolve) => setTimeout(resolve, ms)); } async function recentReleasesByTag( releaser: Releaser, owner: string, repo: string, tag: string, ): Promise<Release[]> { const matches: Release[] = []; let pages = 0; for await (const page of releaser.allReleases({ owner, repo })) { matches.push(...page.data.filter((release) => release.tag_name === tag)); pages += 1; if (pages >= RECENT_RELEASE_SCAN_PAGES) { break; } }
This is related to the scalability concern in #724, but it is a different failure mode: the repository has far fewer than 10,000 releases; the response for 100 releases is large because it embeds metadata for many assets.
A metadata-only lookup (for example via GraphQL), or another approach that avoids one very large REST response, may preserve draft-release detection without this timeout. Simply creating after a list failure may risk duplicating an existing draft release, so that fallback would need care.
Activity