rust-lang/cargo · error
probably rustup rustc, but without rustup's env vars
Error message
probably rustup rustc, but without rustup's env vars
What it means
When computing the rustc fingerprint, Cargo detects that the resolved rustc is the rustup shim (rustup_rustc == rustc) but neither RUSTUP_HOME nor RUSTUP_TOOLCHAIN is set. Without those env vars Cargo cannot mix the real toolchain's identity/mtime into the fingerprint, so it conservatively bails rather than risk stale caches when rustup swaps the compiler.
Solutions
- Let cargo be launched through rustup normally so RUSTUP_HOME/RUSTUP_TOOLCHAIN are set.
- Set RUSTC to the concrete toolchain binary (e.g. ~/.rustup/toolchains/stable-.../bin/rustc) instead of the shim.
- Export RUSTUP_HOME and RUSTUP_TOOLCHAIN explicitly in the launch environment.
- Run `rustup which rustc` to confirm rustup can resolve the toolchain.
Example fix
# before # RUSTC=~/.cargo/bin/rustc cargo build # shim without env # after # unset RUSTC # cargo build # let rustup set RUSTUP_HOME / RUSTUP_TOOLCHAIN
Defensive patterns
Strategy: validation
Validate before calling
fn rustup_env_present() -> bool {
std::env::var("RUSTUP_HOME").is_ok() && std::env::var("RUSTUP_TOOLCHAIN").is_ok()
}
// if std::env::var("RUSTC").map(|p| p.ends_with("rustup") || p.contains("cargo/bin/rustc")).unwrap_or(false) {
// assert!(rustup_env_present(), "rustup shim selected without RUSTUP_HOME/RUSTUP_TOOLCHAIN");
// } Type guard
fn resolves_to_rustup_shim(rustc: &std::path::Path) -> bool {
rustc.file_name() == Some(std::ffi::OsStr::new("rustc"))
&& rustc.starts_with(home::cargo_home().unwrap_or_default().join("bin"))
} Prevention
- Do not pin RUSTC to the rustup proxy; let rustup choose the toolchain.
- In IDEs/servers, preserve RUSTUP_HOME and RUSTUP_TOOLCHAIN in the child env.
- If you must bypass rustup, set RUSTC to the concrete toolchain binary.
When it happens
Trigger: Cargo invoked such that rustup's shim is used but rustup's environment variables are absent — e.g. cargo started by a parent that scrubbed env, invoking ~/.cargo/bin/rustc directly as RUSTC, or a broken rustup install.
Common situations: IDE/build-server env sanitization stripping RUSTUP_*; sandboxed/containerized runs that copy the shim but not the env; pinning RUSTC to the rustup proxy manually.
Related errors
- could not find rustup home dir
- does not exist, unable to build with the standard library…
- does not exist, unable to build with the standard library…
- Cargo couldn't find your home directory. This probably…
- $CARGO not set
AI-assisted analysis of rust-lang/cargo@42eee92bc9 (2026-08-11).
Data as JSON: /api/errors/5a4c410475cd17bf.
Report an issue: GitHub.
Appendix: source
Thrown at src/util/rustc.rs:378
let maybe_rustup = rustup_rustc == rustc;
match (
maybe_rustup,
gctx.get_env("RUSTUP_HOME"),
gctx.get_env("RUSTUP_TOOLCHAIN"),
) {
(_, Ok(rustup_home), Ok(rustup_toolchain)) => {
debug!("adding rustup info to rustc fingerprint");
rustup_toolchain.hash(&mut hasher);
rustup_home.hash(&mut hasher);
let real_rustc = Path::new(&rustup_home)
.join("toolchains")
.join(rustup_toolchain)
.join("bin")
.join("rustc")
.with_extension(env::consts::EXE_EXTENSION);
paths::mtime(&real_rustc)?.hash(&mut hasher);
}
(true, _, _) => anyhow::bail!("probably rustup rustc, but without rustup's env vars"),
_ => (),
}
Ok(Hasher::finish(&hasher))
}
fn process_fingerprint(cmd: &ProcessBuilder, extra_fingerprint: u64) -> u64 {
let mut hasher = StableHasher::new();
extra_fingerprint.hash(&mut hasher);
cmd.get_args().for_each(|arg| arg.hash(&mut hasher));
let mut env = cmd.get_envs().iter().collect::<Vec<_>>();
env.sort_unstable();
env.hash(&mut hasher);
Hasher::finish(&hasher)
}
View on GitHub (pinned to 42eee92bc9)