Repository navigation
[BUG]: CI: prior-branch lookup fails when gh run list returns a stale slice missing recent runs #2975
Description
Problem
The prior-branch artifact lookup in ci/tools/lookup-run-id (hardened by #2643) has a known-latent gap that surfaced repeatedly today (2026-09-30): gh run list --branch 12.9.x --workflow CI --status success --limit 100 intermittently returns a bounded candidate set that omits the newest runs. When every returned candidate is older than the 90-day GitHub Actions artifact retention, all lookups fail with:
Error: No successful 'CI' run on branch '12.9.x' has all required artifacts
Ralf explicitly deferred this class in #2643:
This intentionally does not eliminate the possibility that GitHub's server-side branch filter returns a stale or incomplete bounded candidate set; that broader lookup redesign remains outside #2642.
Evidence
The 12.9.x branch has four fresh successful CI runs (all carrying the required cuda-bindings-python*-cuda12.9.1-* artifacts, unexpired):
$ gh api "repos/NVIDIA/cuda-python/actions/workflows/ci.yml/runs?branch=12.9.x&status=success&per_page=5" \
--jq '.workflow_runs[] | [.id, .created_at]'
[35797318627, "2026-09-22T23:25:12Z"]
[35362127153, "2026-09-18T15:23:32Z"]
[35166820782, "2026-09-17T00:30:14Z"]
[34881968601, "2026-09-14T18:37:49Z"]
[31739833756, "2026-08-13T20:14:11Z"]
Three CI jobs today independently invoked lookup-run-id and each received a different stale slice, none containing any 2026-09 run:
| Job | Time (UTC) | Newest run in slice | Slice size | Result |
|---|---|---|---|---|
#2920, aarch64 / py3.11 build |
14:29:04 | 22911991598 (2026-03-10) | 12 | fail |
#2965, linux-64 / py3.10 build |
17:04:06 | 23885913601 (2026-04-02) | 13 | fail |
#2965, linux-64 / py3.14t test |
17:24:02 | 26890119460 (2026-06-03) | 14 | fail |
Sibling matrix rows in the same runs made the same lookup within seconds and mostly got fresher slices, so this manifests as a per-row flake. #2965's py3.10 build passed on run_attempt: 2 with no code change, confirming the flake is API-side.
Root cause
gh run list --branch --workflow --status success --limit 100 occasionally returns a bounded set that omits the true newest runs on the branch. The tool trusts this list as authoritative; when the entire returned slice is older than the 90-day artifact retention, every candidate fails the artifact-freshness check and the step errors out. This is the residual API-caching risk Ralf called out in #2643.
Possible mitigations
- Cross-check
gh run listagainst a direct REST call to/repos/{r}/actions/workflows/ci.yml/runs?branch=X&status=success&per_page=100, union the results, then sort. A local replay of this endpoint today consistently returned all 2026-09 runs even while the CI'sgh run listdid not. - Look up the branch HEAD SHA (
/repos/{r}/branches/12.9.x) first and try the run for that SHA before falling back to the list. - Retry
gh run listonce with a short delay after exhausting candidates; the stale slice usually clears on a second call. - On final failure, emit a diagnostic that dumps the returned slice and the branch HEAD, so a reviewer doesn't have to reproduce the API state to see what happened.
-- Leo's bot
Activity
leofang commentedon Sep 30, 2026
@jpascucci-nv would you be able to help take a look? 🙂
jpascucci-nv commentedon Sep 30, 2026
@leofang Gemini has a different solution.
(links to github issues can be found by clicking the above link, the copy-paste dropped them)
jpascucci-nv commentedon Sep 30, 2026
This shouldn't. have been closed.
Closes NVIDIA#2975 (NVIDIA#2976)
jpascucci-nv commentedon Oct 2, 2026
It looks like the fix didn't work, there was a nightly build job which failed with https://github.com/NVIDIA/cuda-python/actions/runs/37013218624/job/110862010965 . I'll try one of the alternate methods.
leofang commentedon Oct 2, 2026
Not related to
lookup-run-idbut same class of errors: I manually triggered the nightly-optional-deps CI and saw that it fetches from a terribly old commit (1db44ec is from two weeks ago):https://github.com/NVIDIA/cuda-python/actions/runs/37046383242/job/110968754150#step:3:39
leofang commentedon Oct 2, 2026
Replying to @leofang's note above — this one actually is
lookup-run-id. Step 3 offind-wheelsis literally this call (log line 172 in the step):The step didn't error — it reported
Found run ID: 35686532745and exited 0 — but that run is from 2026-09-22T04:20Z. At the timefind-wheelsran (2026-10-02T18:17Z) the true newest successfulCIrun onmainwas 37013218624 (2026-10-02T13:28Z), and four more fresher successes also existed (36822…, 36917…, 36931…, 36938…). None of them appeared in the slicegh run listreturned, so the first candidate was the Sep 22 one — and branch-mode inlookup-run-idaccepts the first candidate unconditionally when no--artifactis passed, so it was returned.So the bug is the same as before, with
--branch maindoing the work--status successused to do: community#24626 explicitly listsbranch,status, andcreatedas all affected by the stale-slice behavior. #2976 dropping--statuslikely reduced the flake rate but didn't close it. @jpascucci-nv's earlier example (runs/37013218624/job/110862010965, 2026-10-02T13:47Z) is the same tool in the loud failure mode — the test-wheel-windows path passes--artifact, so it iterates candidates, exhausts the stale slice, and errors.Worth noting the failure mode is now silent when no
--artifactis passed: before #2976 the typical signature was a loudError: No successful 'CI' run on branch has all required artifacts; now the tool returns a stale-but-unexpired run and downstream jobs break far away. Four of today's failing nightly jobs die atDisplay structure of downloaded cuda-python artifactswithls: cannot access 'cuda_python*.whl': No such file or directory(e.g. this one) because the Sep 22 run's artifact set doesn't match today's test code.Mitigations, roughly cheapest first:
gh api repos/{r}/branches/main) first and try the run for that SHA; use the list query only as a fallback when HEAD has no successful run yet.--branchfromgh run listtoo (keep only--workflow), filter branch client-side — matches 24626's "unfiltered + client-side" workaround (10/10 correct in the thread).gh run listonce on a short backoff if the top candidate is older than N hours — the stale slice usually clears on a second call.--artifactisn't passed (e.g. require at least a HEAD-SHA-recent-ness check), so a silently-stale pick becomes a loud skip.-- Leo's bot
ci: resolve branch run by walking HEAD history (#3013)
leofang commentedon Oct 6, 2026
#3013 was merged. Let's keep an eye on this.
leofang commentedon Oct 9, 2026
Our admins opened a support ticket w/ GH (4817893). GH Support noted that this issue should be mitigated now. I have my bot running a sweep to see if the same error still happens since #3013 was merged. Though even if there is 0 error that happened since then, it's hard to say whether it's our #3013 fix or GH's fix taking effect, in particular considering we basically (almost) follow the same suggestion that GH provided:
leofang commentedon Oct 9, 2026
doesn't seem to find anything unusual, let's close this for now