rust-lang/cargo · error

$CARGO not set

Error message

$CARGO not set

What it means

cargo_exe (mod.rs:553-604) resolves the path to the running `cargo` binary. It tries current_exe() and argv[0] first; if neither yields a path whose file_stem is 'cargo', it falls back to the $CARGO environment variable. If $CARGO is also unset, it bails '$CARGO not set'. This fallback exists for cargo-as-library consumers, valgrind, ld.so, or cargo-* subcommand wrappers where current_exe/argv0 are not 'cargo'.

Source

Thrown at src/context/mod.rs:564

                None
            },
            self,
        )
    }

    /// Gets the path to the `cargo` executable.
    pub fn cargo_exe(&self) -> CargoResult<&Path> {
        self.cargo_exe
            .try_borrow_with(|| {
                let from_env = || -> CargoResult<PathBuf> {
                    // Try re-using the `cargo` set in the environment already. This allows
                    // commands that use Cargo as a library to inherit (via `cargo <subcommand>`)
                    // or set (by setting `$CARGO`) a correct path to `cargo` when the current exe
                    // is not actually cargo (e.g., `cargo-*` binaries, Valgrind, `ld.so`, etc.).
                    let exe = self
                        .get_env_os(crate::CARGO_ENV)
                        .map(PathBuf::from)
                        .ok_or_else(|| anyhow!("$CARGO not set"))?;
                    Ok(exe)
                };

                fn from_current_exe() -> CargoResult<PathBuf> {
                    // Try fetching the path to `cargo` using `env::current_exe()`.
                    // The method varies per operating system and might fail; in particular,
                    // it depends on `/proc` being mounted on Linux, and some environments
                    // (like containers or chroots) may not have that available.
                    let exe = env::current_exe()?;
                    Ok(exe)
                }

                fn from_argv() -> CargoResult<PathBuf> {
                    // Grab `argv[0]` and attempt to resolve it to an absolute path.
                    // If `argv[0]` has one component, it must have come from a `PATH` lookup,
                    // so probe `PATH` in that case.
                    // Otherwise, it has multiple components and is either:
                    // - a relative path (e.g., `./cargo`, `target/debug/cargo`), or

View on GitHub (pinned to 0e07a15537)

Solutions

  1. Set `CARGO` to the absolute path of the cargo binary before invoking the process.
  2. Name the binary 'cargo' or invoke it through a normal PATH lookup so argv[0]/current_exe resolve correctly.
  3. Ensure /proc is mounted on Linux (current_exe depends on it).

Example fix

# before
valgrind my-cargo-wrapper build   # current_exe/argv0 obscured
# after
export CARGO=$(command -v cargo)
valgrind my-cargo-wrapper build
Defensive patterns

Strategy: validation

Validate before calling

# For cargo-as-library or wrapper binaries, set CARGO explicitly:
export CARGO="${CARGO:-$(command -v cargo)}"
exec "$CARGO" "$@"

Prevention

When it happens

Trigger: Using cargo as a library from a binary that is not named cargo, under a launcher (valgrind/ld.so/wrapper) that obscures argv[0] and current_exe, without setting $CARGO. Also when cargo needs to re-invoke itself (e.g. `cargo invoke`) but cannot locate its own binary.

Common situations: A custom cargo-* subcommand that links against the cargo crate; running cargo under valgrind or a dynamic linker; stripped/oddly-named binaries.

Related errors


AI-assisted analysis of rust-lang/cargo@0e07a15537 (2026-08-06). Data as JSON: /data/errors/f5c6af20b69d89a6.json. Report an issue: GitHub.