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

  1. Let cargo be launched through rustup normally so RUSTUP_HOME/RUSTUP_TOOLCHAIN are set.
  2. Set RUSTC to the concrete toolchain binary (e.g. ~/.rustup/toolchains/stable-.../bin/rustc) instead of the shim.
  3. Export RUSTUP_HOME and RUSTUP_TOOLCHAIN explicitly in the launch environment.
  4. 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

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


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)