rust-lang/cargo · error · anyhow::Error

failed to connect to jobserver from environment variable

Error message

failed to connect to jobserver from environment variable `{name}={value:?}`: {e}

What it means

Cargo tried to attach to an existing GNU make jobserver (semaphore-based parallelism via the `MAKEFLAGS`/`CARGO_MAKEFLAGS` env var) advertised in the environment, and the jobserver crate returned an error other than the benign `NoEnvVar`/`NoJobserver`/`NegativeFd`/`Unsupported`. The failing variable name, its raw value, and the underlying error are surfaced.

Solutions

  1. Unset the offending variable before invoking cargo: `unset MAKEFLAGS; cargo build`.
  2. Pass `--jobs N` to cargo explicitly to bypass the inherited jobserver.
  3. Ensure the parent `make` invocation actually creates the jobserver (`make -j4`, not `make`).
  4. Update the jobserver-providing tool (make 4.x, ninja) so the auth FDs are inheritable.

Example fix

// before
make -j4   # Makefile rule: cargo build
# inherits a jobserver FD that is closed -> error

// after
# Makefile
build:
	+unset MAKEFLAGS; cargo build --jobs 4
# or
build:
	+cargo build --jobs 4
Defensive patterns

Strategy: validation

Validate before calling

fn jobserver_env_valid() -> bool {
    if let Ok(mf) = std::env::var("MAKEFLAGS") {
        if mf.contains("--jobserver-auth=") {
            // FDs must be open and inheritable; conservative check
            return std::env::current_exe().is_ok();
        }
    }
    true
}

Type guard

null

Try / catch

match GlobalContext::load_jobserver() {
    Err(e) if e.to_string().contains("failed to connect to jobserver") => { std::env::remove_var("MAKEFLAGS"); retry_without_jobserver()? }
    r => r?,
}

Prevention

When it happens

Trigger: Parent process exports a `MAKEFLAGS` containing a jobserver spec (`--jobserver-auth=<fds>`) but the file descriptors are invalid/closed; running under `make -jN` where the FDs were not inherited (e.g. cargo was exec'd after closing FDs); a stale `CARGO_MAKEFLAGS` from a previous make session.

Common situations: CI that wraps cargo in `make` and accidentally re-execs; containers that strip inherited FDs; custom build orchestrators that set `MAKEFLAGS` without providing live FDs; `make` older than 4.4 with incompatible auth syntax.

Related errors


AI-assisted analysis of rust-lang/cargo@98a09e7e7d (2026-08-11). Data as JSON: /api/errors/a72153de3d1abd8b. Report an issue: GitHub.

Appendix: source

Thrown at src/context/mod.rs:339

                let jobserver::FromEnv { client, var } =
                    unsafe { jobserver::Client::from_env_ext(true) };

                match client {
                    Ok(client) => return Ok(Some(client)),
                    Err(e)
                        if matches!(
                            e.kind(),
                            FromEnvErrorKind::NoEnvVar
                                | FromEnvErrorKind::NoJobserver
                                | FromEnvErrorKind::NegativeFd
                                | FromEnvErrorKind::Unsupported
                        ) =>
                    {
                        Ok(None)
                    }
                    Err(e) => {
                        let (name, value) = var.unwrap();
                        Err(anyhow::anyhow!(
                            "failed to connect to jobserver from environment variable `{name}={value:?}`: {e}"
                        ))
                    }
                }
            },
        );
        let jobserver = match &*GLOBAL_JOBSERVER {
            Ok(jobserver) => jobserver.as_ref(),
            Err(e) => {
                let _ = shell.warn(e);
                None
            }
        };

        let env = Env::new();

        let cache_key = "CARGO_CACHE_RUSTC_INFO";
        let cache_rustc_info = match env.get_env_os(cache_key) {

View on GitHub (pinned to 98a09e7e7d)