From 6b4db81b4ef313564e3a421f6f78ea5b7fcc1fa2 Mon Sep 17 00:00:00 2001 From: Matt Fogel Date: Wed, 13 May 2026 15:52:10 -0400 Subject: [PATCH 1/4] ci: restore Homebrew stub removal on macOS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR #54 pinned to macos-14 and dropped the PATH workaround on the (incorrect) assumption that macos-14 didn't ship the broken Homebrew `cargo` wrapper. It does — same failure as macos-15, the very next main-push run after PR #54 broke. Re-runs reproduce deterministically. Restore the stub-removal approach from the closed PR #53, this time on top of the macos-14 pin so we get both: the marginally healthier runner image and an active defense that doesn't rely on PATH ordering. This is the version that should have shipped originally. --- .github/workflows/ci.yml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1c5ba63..3f89de7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,13 +20,20 @@ jobs: strategy: fail-fast: false matrix: - # Pinned to macos-14 instead of macos-latest: macos-15 ships a - # broken Homebrew cargo wrapper that dispatches to rustup-init. - # See actions/runner-images#13985. os: [ubuntu-latest, macos-14] steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable @ 2026-05-13 + # macOS runner images ship Homebrew `cargo`/`rustc` wrappers that + # dispatch to rustup-init and fail with "unexpected argument 'build'". + # Remove them so the rustup-managed proxies in ~/.cargo/bin (installed + # by dtolnay above) are the only ones available — eliminates the race. + - name: remove Homebrew rust stubs on macOS + if: runner.os == 'macOS' + run: | + for tool in cargo rustc rustup rustdoc rust-gdb rust-lldb rust-analyzer; do + rm -f "/opt/homebrew/bin/$tool" "/usr/local/bin/$tool" + done - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 - name: cargo build run: cargo build --workspace --all-targets --locked From 9b81197b93af058d210e33f5d950aa981cca6577 Mon Sep 17 00:00:00 2001 From: Matt Fogel Date: Wed, 13 May 2026 15:59:42 -0400 Subject: [PATCH 2/4] ci: invoke cargo via absolute path to sidestep broken Homebrew stub MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The earlier stub-removal step ran successfully but cargo build still failed with the same rustup-init error — there's a third location of the broken cargo wrapper we never found. Stop hunting for it. Invoke cargo via \$HOME/.cargo/bin/cargo directly. dtolnay/rust-toolchain installs the rustup-managed proxies there on every OS, so the same absolute path works for both Ubuntu and macOS — no matrix-conditional logic needed. When GitHub fixes the runner image upstream, this is a trivial one-line revert. --- .github/workflows/ci.yml | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3f89de7..7f5603b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,21 +24,18 @@ jobs: steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable @ 2026-05-13 - # macOS runner images ship Homebrew `cargo`/`rustc` wrappers that - # dispatch to rustup-init and fail with "unexpected argument 'build'". - # Remove them so the rustup-managed proxies in ~/.cargo/bin (installed - # by dtolnay above) are the only ones available — eliminates the race. - - name: remove Homebrew rust stubs on macOS - if: runner.os == 'macOS' - run: | - for tool in cargo rustc rustup rustdoc rust-gdb rust-lldb rust-analyzer; do - rm -f "/opt/homebrew/bin/$tool" "/usr/local/bin/$tool" - done - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 + # Invoke cargo via its absolute path rather than relying on PATH lookup. + # macOS runner images currently ship a broken Homebrew `cargo` wrapper + # that dispatches to `rustup-init` and fails with "unexpected argument + # 'build'". Using $HOME/.cargo/bin/cargo (where dtolnay installs the + # rustup-managed proxies) sidesteps the broken stub entirely. The same + # path works on Ubuntu, so we use it uniformly. Refs: + # actions/runner-images#13985, Homebrew/homebrew-core#178311. - name: cargo build - run: cargo build --workspace --all-targets --locked + run: $HOME/.cargo/bin/cargo build --workspace --all-targets --locked - name: cargo test - run: cargo test --workspace --all-targets --locked + run: $HOME/.cargo/bin/cargo test --workspace --all-targets --locked lint: name: lint @@ -50,6 +47,6 @@ jobs: components: clippy, rustfmt - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 - name: cargo fmt - run: cargo fmt --all -- --check + run: $HOME/.cargo/bin/cargo fmt --all -- --check - name: cargo clippy - run: cargo clippy --workspace --all-targets --locked -- -D warnings + run: $HOME/.cargo/bin/cargo clippy --workspace --all-targets --locked -- -D warnings From ca46e72adf7e3e6136f0cda44fcd11d9b7eefa63 Mon Sep 17 00:00:00 2001 From: Matt Fogel Date: Wed, 13 May 2026 16:01:40 -0400 Subject: [PATCH 3/4] debug: log macOS toolchain state to find broken cargo source --- .github/workflows/ci.yml | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7f5603b..997a21e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,18 +24,26 @@ jobs: steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable @ 2026-05-13 + - name: debug toolchain state (post-dtolnay, pre-cache) + run: | + echo "=== which cargo ==="; which cargo || true + echo "=== PATH ==="; echo "$PATH" + echo "=== ls ~/.cargo/bin ==="; ls -la "$HOME/.cargo/bin/" 2>&1 || true + echo "=== file ~/.cargo/bin/cargo ==="; file "$HOME/.cargo/bin/cargo" 2>&1 || true + echo "=== ~/.cargo/bin/cargo --version ==="; "$HOME/.cargo/bin/cargo" --version 2>&1 || true + echo "=== ls ~/.rustup ==="; ls -la "$HOME/.rustup/" 2>&1 || true + echo "=== ls ~/.rustup/toolchains ==="; ls -la "$HOME/.rustup/toolchains/" 2>&1 || true + echo "=== rustup show ==="; rustup show 2>&1 || true - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 - # Invoke cargo via its absolute path rather than relying on PATH lookup. - # macOS runner images currently ship a broken Homebrew `cargo` wrapper - # that dispatches to `rustup-init` and fails with "unexpected argument - # 'build'". Using $HOME/.cargo/bin/cargo (where dtolnay installs the - # rustup-managed proxies) sidesteps the broken stub entirely. The same - # path works on Ubuntu, so we use it uniformly. Refs: - # actions/runner-images#13985, Homebrew/homebrew-core#178311. + - name: debug toolchain state (post-cache) + run: | + echo "=== ls ~/.cargo/bin ==="; ls -la "$HOME/.cargo/bin/" 2>&1 || true + echo "=== file ~/.cargo/bin/cargo ==="; file "$HOME/.cargo/bin/cargo" 2>&1 || true + echo "=== ~/.cargo/bin/cargo --version ==="; "$HOME/.cargo/bin/cargo" --version 2>&1 || true - name: cargo build - run: $HOME/.cargo/bin/cargo build --workspace --all-targets --locked + run: cargo build --workspace --all-targets --locked - name: cargo test - run: $HOME/.cargo/bin/cargo test --workspace --all-targets --locked + run: cargo test --workspace --all-targets --locked lint: name: lint @@ -47,6 +55,6 @@ jobs: components: clippy, rustfmt - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 - name: cargo fmt - run: $HOME/.cargo/bin/cargo fmt --all -- --check + run: cargo fmt --all -- --check - name: cargo clippy - run: $HOME/.cargo/bin/cargo clippy --workspace --all-targets --locked -- -D warnings + run: cargo clippy --workspace --all-targets --locked -- -D warnings From 346c0274d939d49703806b70a13fa4b954e4c989 Mon Sep 17 00:00:00 2001 From: Matt Fogel Date: Wed, 13 May 2026 16:03:49 -0400 Subject: [PATCH 4/4] ci: fix poisoned Swatinem cache breaking macOS cargo build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause finally found via debug output: the Swatinem cache contains a poisoned ~/.cargo/bin/rustup symlink that points at /opt/homebrew/bin/rustup-init (Homebrew's broken wrapper). dtolnay installs a working ~/.cargo/bin/rustup as a real 11MB Mach-O binary; Swatinem then restores the symlink over it, and every subsequent `cargo build` resolves through the broken Homebrew binary and fails with "unexpected argument 'build'". Fix in one diff: - `cache-bin: "false"` — stop caching ~/.cargo/bin entirely. We don't need it cached; dtolnay installs fresh every run in seconds. - `prefix-key: "v1-rust"` — bump the cache-key namespace so the existing poisoned cache entries are abandoned and a clean cache is built from scratch. Both options applied uniformly to the test and lint jobs. --- .github/workflows/ci.yml | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 997a21e..4368fd1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,22 +24,16 @@ jobs: steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable @ 2026-05-13 - - name: debug toolchain state (post-dtolnay, pre-cache) - run: | - echo "=== which cargo ==="; which cargo || true - echo "=== PATH ==="; echo "$PATH" - echo "=== ls ~/.cargo/bin ==="; ls -la "$HOME/.cargo/bin/" 2>&1 || true - echo "=== file ~/.cargo/bin/cargo ==="; file "$HOME/.cargo/bin/cargo" 2>&1 || true - echo "=== ~/.cargo/bin/cargo --version ==="; "$HOME/.cargo/bin/cargo" --version 2>&1 || true - echo "=== ls ~/.rustup ==="; ls -la "$HOME/.rustup/" 2>&1 || true - echo "=== ls ~/.rustup/toolchains ==="; ls -la "$HOME/.rustup/toolchains/" 2>&1 || true - echo "=== rustup show ==="; rustup show 2>&1 || true - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 - - name: debug toolchain state (post-cache) - run: | - echo "=== ls ~/.cargo/bin ==="; ls -la "$HOME/.cargo/bin/" 2>&1 || true - echo "=== file ~/.cargo/bin/cargo ==="; file "$HOME/.cargo/bin/cargo" 2>&1 || true - echo "=== ~/.cargo/bin/cargo --version ==="; "$HOME/.cargo/bin/cargo" --version 2>&1 || true + with: + # Do NOT cache ~/.cargo/bin. A prior macOS run captured a poisoned + # ~/.cargo/bin/rustup symlink pointing at /opt/homebrew/bin/rustup-init + # (Homebrew's broken wrapper). Every restore overwrote the working + # rustup that dtolnay installs, breaking `cargo build` with + # "unexpected argument 'build'". prefix-key is bumped to evict the + # existing poisoned cache entries. + cache-bin: "false" + prefix-key: "v1-rust" - name: cargo build run: cargo build --workspace --all-targets --locked - name: cargo test @@ -54,6 +48,9 @@ jobs: with: components: clippy, rustfmt - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 + with: + cache-bin: "false" + prefix-key: "v1-rust" - name: cargo fmt run: cargo fmt --all -- --check - name: cargo clippy