Repository navigation
Nightly regression: 6 tests in test_graph_builder.py fail intermittently on linux-aarch64 py3.14/3.14t since #2008 #2290
Description
Since #2008 merged on 2026-06-29, the Nightly standard (linux-aarch64) / Python 3.14, CUDA 13.3.0 (local), GPU l4 (x2) job (and its 3.14t sibling) in the "CI: Nightly optional-deps" workflow has intermittently failed on the same 6 tests in cuda_core/tests/graph/test_graph_builder.py (all newly added in #2008):
test_graph_begin_building_twice— raisesCUDAError(CUDA_ERROR_ILLEGAL_STATE)instead of the expectedRuntimeError("Graph builder is already building.")test_graph_split_requires_building—DID NOT RAISE RuntimeError(expected:"Graph builder must be building before it can be split.")test_graph_complete_after_close_forked— raisesRuntimeError("Graph has not finished building.")instead of"Graph builder has been closed."test_graph_update_after_source_close—TypeError: int() argument must be … not 'NoneType'at_graph_builder.pyx:843, instead ofValueError("Source graph builder has been closed.")test_graph_embed_non_builder—AttributeError: 'object' object has no attribute '_building_ended'at_graph_builder.pyx:689, instead of the intendedTypeErrorfrom the isinstance checktest_graph_close_is_idempotent— aftergraph.close()called twice,int(graph.handle) == 0fails becausegraph.handleisNone(not the null-int handle the assertion expects)
Nightly history on main
| Date | HEAD | aarch64 py3.14 | Notes |
|---|---|---|---|
| 2026-06-28 | ea0215fd09 |
✅ pass | pre-#2008 |
| 2026-06-29 | ea0215fd09 |
✅ pass | ran 03:25 UTC, before #2008 merged (21:04 UTC same day) |
| 2026-06-30 | dad6a421df |
❌ 6 graph_builder tests fail — py3.14 / py3.14t | first nightly after #2008 (merge commit) |
| 2026-07-01 | f9f3849bd8 |
❌ (unrelated nvshmem failure) — py3.14 / py3.14t | graph_builder tests passed this night; only test_locate_bitcode_lib[nvshmem_device] failed (a separate, already-fixed issue via #2286) |
Also observed on PR #2283 push run ec04c554bd at 2026-07-01T17:48 UTC — same 6 graph_builder failures — py3.14 / py3.14t. Then a /ok to test rerun of the exact same tree (synthetic head 58fd95efb4, run 28542961462) passed all 6.
Direct link into the failure block for the 2026-06-30 run: https://github.com/NVIDIA/cuda-python/actions/runs/28418107489/job/84205333659#step:35:3873
Diagnosis
Two observed failures, two observed passes on the same tree — so the tests exhibit non-deterministic behavior on linux-aarch64 py3.14/3.14t (L4 x2). pytest-randomly is in the test group, which reshuffles order per invocation; some of the 6 failures (e.g. test_graph_close_is_idempotent finding graph.handle is None where the test expects int(graph.handle) == 0) point at test-to-test state leakage or a lifecycle assumption that only holds under a specific ordering. Not observed on linux-64, win-64, or linux-aarch64 py3.12/3.13.
Because #2008 introduced both the tests and the underlying refactor, the fix should live either in _graph_builder.pyx (make the invariants hold regardless of ordering) or in the new tests (make them order-independent — e.g. assert graph.handle in (0, None)), whichever matches the intended semantics.
cc @Andy-Jost
Activity
Andy-Jost commentedon Jul 6, 2026
Root cause: stale/version-skewed
cuda.corebinary — not a runtime bug or test-ordering issueI dug into the actual failing job log (run
28418107489, job84205333659) rather than the summarized error text, and I'm confident these 6 failures are a build-artifact version skew: the compiledcuda.core.graph._graph_builderunder test was built from pre-#2008 source, while the test files and.pyxon disk are post-#2008. Every failure is a new test hitting old compiled behavior, and the reported.pyxline numbers map to the pre-#2008 file while pytest prints the post-#2008 source.Evidence (all six point the same way):
test_graph_embed_non_builder→AttributeError: 'object' object has no attribute '_building_ended'at_graph_builder.pyx:689._building_endedexists nowhere in cuda.core: Cythonize GraphBuilder and Graph with handle-layer cleanup #2008 or current source, but atdad6a421df^(the commit before cuda.core: Cythonize GraphBuilder and Graph with handle-layer cleanup #2008) line 689 is exactlyif not child._building_ended:. In cuda.core: Cythonize GraphBuilder and Graph with handle-layer cleanup #2008,embed(self, GraphBuilder child)is Cython-typed, soobject()yieldsTypeErrorat the call boundary.test_graph_update_after_source_close→TypeError: int() ... not 'NoneType'at:843. Pre-cuda.core: Cythonize GraphBuilder and Graph with handle-layer cleanup #2008 line 841 isif not source._building_ended:and the oldupdate()deref'd aNonehandle; cuda.core: Cythonize GraphBuilder and Graph with handle-layer cleanup #2008 checks_state == CLOSEDfirst and:843is inside a docstring.test_graph_begin_building_twice→ the traceback shows:304 raise RuntimeError("...already building.")and then descends intohandle_return → CUDAError(CUDA_ERROR_ILLEGAL_STATE). A bareraisecannot callhandle_return; the line table is from the old binary while pytest prints the new source.test_graph_split_requires_building("DID NOT RAISE") andtest_graph_complete_after_close_forked("Graph has not finished building" instead of "...has been closed") match the old driver-status/_building_endedlogic and are impossible under the current per-instance_statemachine +GB_check_open.test_graph_close_is_idempotent→int(None). OldGraph.handlereturnedNoneafter close; currentas_py()returnsCUgraphExec(0), soint(...) == 0passes.pytest-randomlyis a red herring. Under the failing run's own seed (--randomly-seed=4095826166, printed in the log) thetest_graph_builder.pytests ran in exact source-file order, and the 6 failures are deterministic given the stale binary.Why intermittent: the cuda.core wheel is built with cibuildwheel + sccache + the nv-gha proxy cache and uploaded as an artifact; the test job downloads that wheel and runs repo-checkout tests. When the cache serves a stale
_graph_builderobject/.c, the wheel ships pre-#2008 code; a clean recompile passes — which is exactly why the/ok to testrerun of the same tree (58fd95efb4) went green. It is not GPU- or interpreter-specific; the py3.14/3.14t + aarch64 + L4 signature just reflects which nightly builds happened to hit the stale cache.Repro (any GPU host, any Python — forces the skew):
This reproduces all 6 with the
_building_ended/int(None)/CUDA_ERROR_ILLEGAL_STATEtracebacks, deterministically.Implication: the fix belongs in the build/CI layer (bust the sccache/proxy cache for cuda.core, ensure Cython regenerates
_graph_builder.c, and/or add a build-provenance smoke check), not in_graph_builder.pyxor the tests. In particular, relaxing the assertions (e.g.assert graph.handle in (0, None)) would mask a phantom — the current source already produces the intended errors. Subsequent nightlies have been green, consistent with the cache anomaly having cleared.@leofang — flagging for follow-up on the CI/build-cache side; happy to help add a provenance guard if that's useful.
leofang commentedon Jul 6, 2026
Thanks, Andy (and Andy's agent)! 😄
Closing. The analysis was right that the code and the test mismatched, but wrong that the code (binary wheel) was corrupted.