#5076·rustup

Concurrent proxy startup can delete the active self-updater and remove rustup

Author: cachebagCreated Sep 13, 2026Updated Sep 13, 2026

Problem

Rustup stages every self-update at the shared path $CARGO_HOME/bin/rustup-init.

Normal rustup and proxy invocations such as rustc run updater cleanup on startup. If a proxy starts while self-update is replacing rustup, it can delete the running updater's path.

On Unix, replacement then:

  1. removes the installed rustup;
  2. tries to copy the updater from its now-deleted path;
  3. fails with No such file or directory;
  4. leaves rustup missing.

This seems to be related to #1864, #4648, and #4777.

Reproduction

The reproduction uses isolated test directories and does not affect the user's real rustup installation. I have included a branch with the accompanying changes to demonstrate the bug.

bash
git clone https://github.com/cachebag/rustup.git
cd rustup
git switch demo/self-update-race-before

cargo test \
  --test test_bonanza \
  --no-default-features \
  --features reqwest-rustls-tls,test \
  suite::cli_self_upd::self_update_replacement_survives_proxy_cleanup \
  -- --exact --nocapture

The test deterministically pauses self-update immediately before replacement, starts a real rustc proxy invocation, then resumes replacement.

The vulnerable branch fails with:

error: could not read metadata for file: '.../bin/rustup-init':
No such file or directory
concurrent proxy removed the installed rustup during self-update

For comparison, the same test passes on my branch (which is the PR linked to this issue):

bash
git switch demo/self-update-race-after
cargo test \
  --test test_bonanza \
  --no-default-features \
  --features reqwest-rustls-tls,test \
  suite::cli_self_upd::self_update_replacement_survives_proxy_cleanup \
  -- --exact --nocapture

Expected behavior

Concurrent rustup or proxy invocations must not delete another process's self-update artifact. A failed replacement must leave the previously installed rustup runnable.