rust-lang/cargo · error · anyhow::Error
$CARGO not set
Error message
$CARGO not set
What it means
Thrown inside GlobalContext::cargo_exe() by the from_env closure when the $CARGO environment variable is absent. Cargo uses a three-tier fallback chain to locate its own binary: $CARGO first, then env::current_exe(), then argv[0]. This specific error text is produced by the first tier but is only surfaced to the user when all three tiers fail, at which point it is wrapped with the context 'couldn't get the path to cargo executable'.
Solutions
- Set the CARGO environment variable to the absolute path of the cargo binary before invoking the process: `export CARGO=$(which cargo)`
- If running inside a container or chroot, ensure /proc is mounted so env::current_exe() works as a fallback
- If calling Cargo as a library, set CARGO_ENV explicitly via std::env::set_var("CARGO", &cargo_path) before calling cargo_exe()
Example fix
// before: CARGO not set, current_exe is not 'cargo'
let gctx = GlobalContext::default();
let cargo = gctx.cargo_exe()?; // fails
// after: set CARGO before building context
std::env::set_var("CARGO", "/usr/local/bin/cargo");
let gctx = GlobalContext::default();
let cargo = gctx.cargo_exe()?; Defensive patterns
Strategy: validation
Validate before calling
// Validate before calling cargo_exe()
fn ensure_cargo_env() -> Result<(), anyhow::Error> {
if std::env::var_os("CARGO").is_none()
&& std::env::current_exe()
.ok()
.and_then(|p| p.file_stem().map(|s| s == std::ffi::OsStr::new("cargo")))
!= Some(true)
{
let cargo = which::which("cargo")
.map_err(|_| anyhow::anyhow!("cargo not found in PATH and $CARGO not set"))?;
std::env::set_var("CARGO", cargo);
}
Ok(())
} Try / catch
match gctx.cargo_exe() {
Ok(path) => { /* use path */ }
Err(e) => {
// Fallback: search PATH manually
let cargo = which::which("cargo")
.expect("cargo not found in PATH and $CARGO not set");
std::env::set_var("CARGO", &cargo);
}
} Prevention
- Always set CARGO when embedding Cargo as a library
- In Docker containers, ensure /proc is mounted so env::current_exe() works as a fallback
- Use std::env::set_var("CARGO", ...) early in any process that calls cargo library APIs
When it happens
Trigger: Calling GlobalContext::cargo_exe() (or any internal Cargo operation that needs the cargo binary path) in a context where $CARGO is unset, env::current_exe() either fails or does not resolve to a binary named 'cargo', and argv[0] also does not resolve to cargo.
Common situations: Running Cargo as a library (cargo-* subcommand, Valgrind, ld.so) without exporting $CARGO. Containers or chroots where /proc is not mounted so env::current_exe() fails. Executing through a wrapper that strips environment variables.
Related errors
- no argv[0]
- Cargo couldn't find your home directory. This probably…
- config.json not found
- could not find cargo home dir
- could not find rustup home dir
AI-assisted analysis of rust-lang/cargo@98a09e7e7d (2026-08-11).
Data as JSON: /api/errors/f5c6af20b69d89a6.
Report an issue: GitHub.
Appendix: source
Thrown at src/context/mod.rs:560
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`), orView on GitHub (pinned to 98a09e7e7d)