gitbutlerapp/gitbutler · error
Editor exited with non-zero status
Error message
Editor exited with non-zero status
What it means
When building a commit message from an external editor (`from_external_editor`), the CLI spawns the editor via a shell, inherits stdio, and waits for it. If the editor process exits with a non-zero status, this error (with code EditorExitedWithNonZeroStatus) is returned instead of reading the temp file.
Solutions
- Set a known-good editor: `export EDITOR=vim` (or nano/code) and retry.
- In vim, exit normally with :wq instead of :cq.
- Verify the editor binary exists and is executable (`which $EDITOR`).
- If the failure persists, write the message directly with a non-interactive flag (e.g. `but commit -m "message"`) to bypass the editor.
Example fix
// before EDITOR=emacsclient git-style editor launch fails // after export EDITOR="emacsclient -a nano" but commit
Defensive patterns
Strategy: try-catch
Validate before calling
const ed = process.env.EDITOR || process.env.GIT_EDITOR;
if (!ed || !commandExists(ed.split(' ')[0])) console.warn(`editor '${ed}' not found; set EDITOR to an installed editor`); Try / catch
match CommitMessage::from_editor(&tempfile) {
Err(e) if e.to_string().contains("non-zero status") => {
eprintln!("editor failed; check EDITOR and exit the editor normally (:wq, not :cq)");
Err(e)
}
other => other,
} Prevention
- Pin EDITOR to a known-working, installed editor.
- Never abort editors with :cq/:q! when the CLI should proceed.
- Use -m flags in non-interactive/CI contexts to skip the editor entirely.
When it happens
Trigger: The configured GIT_EDITOR/core.editor exits non-zero — editor crashed, user aborted in vim with :cq, editor binary not found under the invoked name, or the editor wrote to a read-only temp file.
Common situations: vim/nvim `:cq` usage; bad EDITOR variable pointing to a non-executable or missing program; editor opening a GUI and failing silently; shell wrapper quoting issues.
Related errors
- EditorExitedWithNonZeroStatus
- Editor cancelled
- Editor exited with non-zero status
- Aborting due to empty branch name
- Aborting due to empty
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/b8ac382f7bb96cd6.
Report an issue: GitHub.
Appendix: source
Thrown at crates/but/src/tui/get_text.rs:120
if !initial_text.ends_with('\n') {
writeln!(&mut tempfile)?;
}
writeln!(&mut tempfile, "{REST_TEXT_MARKER}")?;
writeln!(&mut tempfile, "{rest_text}")?;
}
// The editor command is allowed to be a shell expression, e.g. "code --wait" is somewhat common.
// We need to execute within a shell to make sure we don't get "No such file or directory" errors.
let status = gix::command::prepare(editor_cmd)
.arg(tempfile.path())
.stdin(std::process::Stdio::inherit())
.stdout(std::process::Stdio::inherit())
.with_shell()
.spawn()?
.wait()?;
if !status.success() {
return Err(anyhow::anyhow!("Editor exited with non-zero status")
.context(Code::EditorExitedWithNonZeroStatus));
}
Ok(std::fs::read(&tempfile)
.context("failed to read contents of commit message file")?
.into())
}
/// Launch the built-in TUI editor.
fn from_builtin_editor(
filename_safe_intent: &str,
initial_text: &str,
rest_text: Option<&str>,
) -> Result<BString> {
// Determine editor mode based on the intent
let mode = if filename_safe_intent.contains("commit") {
super::editor::EditorMode::CommitMessage
} else if filename_safe_intent.contains("branch") {View on GitHub (pinned to 58e5313667)