gitbutlerapp/gitbutler · error

'dot' (graphviz) must be installed on the system

Error message

'dot' (graphviz) must be installed on the system

What it means

Panic while rendering the debug SVG of the commit graph: spawning the external 'dot' executable failed and the code expects Graphviz to be installed. A spawn failure here is almost always ENOENT - the 'dot' binary is absent from the PATH of the running process. The output file (debug-graph-NN.svg, written next to CARGO_MANIFEST_DIR when set) is never produced.

Source

Thrown at crates/but-graph/src/debug.rs:372

    #[tracing::instrument(skip(self))]
    pub fn open_as_svg(&self) {
        use std::{io::Write, process::Stdio, sync::atomic::AtomicUsize};

        static SUFFIX: AtomicUsize = AtomicUsize::new(0);
        let suffix = SUFFIX.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
        let svg_name = format!("debug-graph-{suffix:02}.svg");
        let svg_path = std::env::var_os("CARGO_MANIFEST_DIR")
            .map(std::path::PathBuf::from)
            .unwrap_or_default()
            .join(svg_name);
        let mut dot = std::process::Command::new("dot")
            .args(["-Tsvg", "-o"])
            .arg(&svg_path)
            .stdin(Stdio::piped())
            .stdout(Stdio::piped())
            .stderr(Stdio::piped())
            .spawn()
            .expect("'dot' (graphviz) must be installed on the system");
        dot.stdin
            .as_mut()
            .unwrap()
            .write_all(self.dot_graph_pruned().as_bytes())
            .ok();
        let mut out = dot.wait_with_output().unwrap();
        out.stdout.extend(out.stderr);
        assert!(
            out.status.success(),
            "dot failed: {out}",
            out = out.stdout.as_bstr()
        );

        assert!(
            std::process::Command::new("open")
                .arg(&svg_path)
                .status()
                .unwrap()

View on GitHub (pinned to 2497b8007a)

Solutions

  1. Install Graphviz: 'brew install graphviz' (macOS), 'sudo apt install graphviz' (Debian/Ubuntu), 'choco install graphviz' (Windows)
  2. Confirm 'dot' resolves in the same environment that runs the command: 'which dot'
  3. For GUI-launched processes, extend PATH in the launcher or invoke via a shell that has Graphviz on PATH

Example fix

// before
let mut dot = std::process::Command::new("dot").args(["-Tsvg", "-o"])
    .arg(&svg_path) /* ... */ .spawn()
    .expect("'dot' (graphviz) must be installed on the system");

// after
let mut dot = std::process::Command::new("dot").args(["-Tsvg", "-o"])
    .arg(&svg_path) /* ... */ .spawn()
    .map_err(|e| anyhow::anyhow!("SVG debug output needs Graphviz ('dot') on PATH; install it or fix PATH: {e}"))?;
Defensive patterns

Strategy: validation

Validate before calling

// Check for dot on PATH before entering code that renders SVG debug output
let dot_found = std::env::var_os("PATH")
    .map(|paths| {
        std::env::split_paths(&paths).any(|dir| dir.join("dot").exists())
    })
    .unwrap_or(false);
if !dot_found {
    anyhow::bail!("SVG debug output requires Graphviz; install it or skip --svg");
}

Prevention

When it happens

Trigger: Running the but-graph debug SVG output on a machine without Graphviz; CI images that lack the graphviz package; GUI- or IDE-launched processes whose inherited PATH omits /opt/homebrew/bin or the Graphviz install directory; distroless/scratch containers.

Common situations: Fresh developer machines; macOS Homebrew Graphviz invisible to non-shell parent processes; minimal Docker images used for reproducible test runs.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17). Data as JSON: /api/errors/7a2399b1008baa0d. Report an issue: GitHub.