zed-industries/zed · error

failed to run node --version. stdout: {}, stderr: {}

Error message

failed to run node --version. stdout: {}, stderr: {}

What it means

SystemNodeRuntime::new sanity-checks a system-provided node binary by executing `node --version`. If the process runs but exits non-zero, the failure bails with the captured stdout and stderr. (A failure even to spawn the process produces the earlier `running node from {path}` context instead.)

Source

Thrown at crates/node_runtime/src/node_runtime.rs:868

}

#[derive(Debug, Clone)]
pub struct SystemNodeRuntime {
    node: PathBuf,
    npm: PathBuf,
    scratch_dir: PathBuf,
}

impl SystemNodeRuntime {
    const MIN_VERSION: semver::Version = Version::new(22, 0, 0);
    async fn new(node: PathBuf, npm: PathBuf) -> Result<Self> {
        let output = util::command::new_command(&node)
            .arg("--version")
            .output()
            .await
            .with_context(|| format!("running node from {:?}", node))?;
        if !output.status.success() {
            anyhow::bail!(
                "failed to run node --version. stdout: {}, stderr: {}",
                String::from_utf8_lossy(&output.stdout),
                String::from_utf8_lossy(&output.stderr),
            );
        }
        let version_str = String::from_utf8_lossy(&output.stdout);
        let version = semver::Version::parse(version_str.trim().trim_start_matches('v'))?;
        if version < Self::MIN_VERSION {
            anyhow::bail!(
                "node at {} is too old. want: {}, got: {}",
                node.to_string_lossy(),
                Self::MIN_VERSION,
                version
            )
        }

        let scratch_dir = paths::data_dir().join("node");
        fs::create_dir(&scratch_dir).await.ok();

View on GitHub (pinned to 9d272b0363)

Solutions

  1. Run `node --version` yourself with the same PATH Zed uses — reproduce and read the stderr
  2. Reinstall Node (or fix the version manager shims: `nvm reinstall <version>`, `volta install node`)
  3. Clear quarantine on a copied binary: xattr -d com.apple.quarantine $(which node)
  4. Point Zed at a healthy node via PATH, or remove system node so the bundled runtime is used
Defensive patterns

Strategy: fallback

Validate before calling

async fn node_runs(node: &Path) -> bool {
    util::command::new_command(node)
        .arg("--version")
        .output()
        .await
        .map(|o| o.status.success())
        .unwrap_or(false)
}

Try / catch

match SystemNodeRuntime::new(node, npm).await {
    Err(e) if e.to_string().contains("node --version") => {
        // binary is broken: fall back to the bundled downloader
        NodeRuntime::install_if_needed(&http).await?
    }
    r => r?,
}

Prevention

When it happens

Trigger: The node binary found on PATH executes but errors: a corrupted or wrong-architecture binary that dies on startup, a wrapper/shim (nvm, volta, mise) whose underlying install is broken, or a sandbox/AV blocking the exec so it exits with an error code.

Common situations: Half-finished nvm/volta installs; macOS quarantine attributes on a manually copied node; Docker images where node is a broken symlink shim; SELinux/AppArmor denials.

Related errors


AI-assisted analysis of zed-industries/zed@9d272b0363 (2026-08-20). Data as JSON: /api/errors/78baa986f74267da. Report an issue: GitHub.