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
- Install Graphviz: 'brew install graphviz' (macOS), 'sudo apt install graphviz' (Debian/Ubuntu), 'choco install graphviz' (Windows)
- Confirm 'dot' resolves in the same environment that runs the command: 'which dot'
- 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
- Add graphviz to CI images and dev-container definitions where graph debugging runs
- For GUI-launched processes, verify the launcher's PATH actually contains the Graphviz bin dir
- Keep a non-SVG (text/dot-source) output mode as the fallback when dot is unavailable
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
- valid hex prefix
- object for prefix exists
- failed to create app settings
- all help topics have clap command metadata
- target OID must exist when ahead calculation is enabled
AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17).
Data as JSON: /api/errors/7a2399b1008baa0d.
Report an issue: GitHub.