Issue #550: build_time_dependencies can hang: two grammar-action tests wait on each other’s cargo

Open and answer this issue on GitHub.

ready · opened 2026-10-08 · updated 2026-10-08 · 4 comments

What happened

CI run 692 (develop at 0.0.673, 80d359d), job rust_floor: scripts/check-floor.sh ran the release suite on the floor toolchain. tests/build_time_dependencies.rs hung until the job’s 90-minute timeout.

13:11:50 test the_build_time_program_links_no_c_library ... ok
13:12:43 test a_grammar_action_calls_a_dependency_at_build_time has been running for over 60 seconds
13:12:43 test a_grammar_action_calls_another_file_of_its_package has been running for over 60 seconds
14:35:32 ##[error]The operation was canceled.

The orphans killed at the end were the test binary, two nikaia processes (one per test), three cargo processes, and one more nikaia under a cargo. That last one is the rustc wrapper, lowering a package.

The same job passed at 0.0.666 (run 685), and bootstrap_compiler passed this test in run 692 itself. So it is intermittent, not a broken test.

Why it matters beyond CI: a hung job holds every later run on develop in the queue, because pushes do not cancel a run in progress. Nothing could reach main for 90 minutes.

Suspected cause (not confirmed)

Nested cargo builds that take locks in different orders:

To build

  1. Reproduce: run build_time_dependencies’s two grammar-action tests concurrently in a loop, release mode (cargo test --release -p nikaia --test build_time_dependencies a_grammar_action). Capture ps and the Blocking waiting for file lock lines when it stalls.
  2. Fix the lock order rather than serialising the tests. Options to check: give the inner build its own CARGO_HOME lock scope, or take a lock of nikaia’s own around the shared target that is never held while waiting on an outer cargo.
  3. A test: two builds of two projects that each run a grammar at build time, started at once, both finish.

Comments

keywan-ghadami, 2026-10-08

A first reproduction attempt, debug build on the stable toolchain, the two tests together five times:

So those two lines alone are the cold build of the shared targets, not a hang. What CI hit was still running 80 minutes later, in release on the floor toolchain with a cold cache. That makes step 1 a cold, release, floor-toolchain run: rustup toolchain install 1.88, a fresh NIKAIA_CACHE_DIR, and the two tests together in a loop.


Generated by Claude Code

keywan-ghadami, 2026-10-08

The floor reproduction did not reproduce it: Rust 1.88, --release, a fresh NIKAIA_CACHE_DIR/XDG_CACHE_HOME, the whole build_time_dependencies file. All six tests passed in 82 s; four of them ran past 60 s on the cold builds and then finished. The same CI job did not hang in run 706 either (0.0.689).

So it is rare. Neither a cold cache nor the floor toolchain is enough on its own. What remains specific to run 692 is a CI runner, which has fewer cores than this machine, with every other test file of the suite running before it in the same cargo test process tree. Reproducing it needs a loop in that environment, or a reading of the lock order (step 2) without a reproduction.


Generated by Claude Code

keywan-ghadami, 2026-10-08

rust_floor is switched off (1132cae, owner’s decision): until Nikaia is stable the suite runs on the current Rust only, and the oldest supported Rust becomes a goal again later. The job stays in .github/workflows/nikaia.yml behind if: false, and promote no longer waits for it.

This hang no longer holds develop up. The suspected cause, nested cargo builds on a target directory the whole machine shares, can still meet a user who builds two projects at once, so the issue stays open for that.


Generated by Claude Code

keywan-ghadami, 2026-10-08

It hung again in run 707 (0.0.690, job 113375175899). The last lines before the cancel were:

Running tests/language.rs (target/floor/release/deps/language-…)
running 2 tests
test the_build_time_package_passes_its_own_tests has been running for over 60 seconds
test the_language_package_passes_its_own_tests has been running for over 60 seconds

So both hang in tests/language.rs. Two nikaia child processes and nested cargo processes were still alive at cleanup. That suggests the two package test runs block each other, for example on a shared cargo target or build-directory lock, when they run in parallel on the floor toolchain.

On the owner’s decision, rust_floor is switched off for now (commit 1132cae, if: false), and promote no longer waits on it. This issue stays open for when the floor job comes back.


Generated by Claude Code

Back to Open Issues