Skip to content

Nightly regression: 6 tests in test_graph_builder.py fail intermittently on linux-aarch64 py3.14/3.14t since #2008 #2290

Closed as not planned

Description

@leofang

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 — raises CUDAError(CUDA_ERROR_ILLEGAL_STATE) instead of the expected RuntimeError("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 — raises RuntimeError("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 of ValueError("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 intended TypeError from the isinstance check
  • test_graph_close_is_idempotent — after graph.close() called twice, int(graph.handle) == 0 fails because graph.handle is None (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

  1. added this to the cuda.core v1.1.0 milestone on Jul 1, 2026
  2. added
    bugSomething isn't working
    P0High priority - Must do!
    cuda.coreEverything related to the cuda.core module
    blockedThis task is currently blocked by other tasks
    and removed
    blockedThis task is currently blocked by other tasks
    on Jul 1, 2026
  3. Andy-Jost commented on Jul 6, 2026

    @Andy-Jost
    Contributor

    Root cause: stale/version-skewed cuda.core binary — not a runtime bug or test-ordering issue

    I dug into the actual failing job log (run 28418107489, job 84205333659) rather than the summarized error text, and I'm confident these 6 failures are a build-artifact version skew: the compiled cuda.core.graph._graph_builder under test was built from pre-#2008 source, while the test files and .pyx on disk are post-#2008. Every failure is a new test hitting old compiled behavior, and the reported .pyx line numbers map to the pre-#2008 file while pytest prints the post-#2008 source.

    Evidence (all six point the same way):

    pytest-randomly is a red herring. Under the failing run's own seed (--randomly-seed=4095826166, printed in the log) the test_graph_builder.py tests 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_builder object/.c, the wheel ships pre-#2008 code; a clean recompile passes — which is exactly why the /ok to test rerun 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):

    git worktree add /tmp/pre2008 dad6a421df^
    cd /tmp/pre2008/cuda_core && pip install -v .
    git checkout dad6a421df -- cuda_core/tests/graph/test_graph_builder.py
    python -m pytest cuda_core/tests/graph/test_graph_builder.py -p no:randomly -v

    This reproduces all 6 with the _building_ended / int(None) / CUDA_ERROR_ILLEGAL_STATE tracebacks, 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.pyx or 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.

  4. leofang commented on Jul 6, 2026

    @leofang
    MemberAuthor

    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.

    • From here, we know that the cuda-core wheel was fetched from this commit on main (each commit on the main branch would go through the full CI tests, with wheels generated and cached in the GHA Artifact space)
    • From here, we know that the tests were fetched from this commit on main
    • the wheel commit was earlier (6/26) than the test commit (the one with cuda.core: Cythonize GraphBuilder and Graph with handle-layer cleanup #2008 merged to main, on 6/29), the reason we fetched wheels from there on 6/30 was because it's the only commit on main that had a green CI check (our binary fetch logic requires a healthy CI status), which is a rare event that could happen and be remedied once a notification system is built ([BUG]: Important CI failures are not team-visible #2204)
      • in particular, we do not rebuild the wheels during nightly tests, and there is no code- or binary- level corruption in the wheel cache/sccache infra as alluded to in the analysis
    • it would add too much complexity to the CI infra in trying to lock the commits in sync between both the code/binary and the repo (for tests), this is an acceptable risk for now
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

P0High priority - Must do!bugSomething isn't workingcuda.coreEverything related to the cuda.core module

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions