aaif-goose/goose · error

Editor exited with non-zero status: {}

Error message

Editor exited with non-zero status: {}

What it means

goose spawns the user's $EDITOR/$VISUAL on a temp file to collect multi-line prompt input (editor.rs). After the child process exits, its exit status is checked; any non-zero exit code produces this error and the edited file is not accepted. The number in the message is the raw exit code (-1 when the process was killed by a signal).

Source

Thrown at crates/goose-cli/src/session/editor.rs:182

        return Err(anyhow::anyhow!("Empty editor command"));
    }

    let mut cmd = Command::new(&parts[0]);
    if let Ok(cwd) = std::env::current_dir() {
        cmd.current_dir(cwd);
    }
    if parts.len() > 1 {
        cmd.args(&parts[1..]);
    }
    cmd.arg(file_path)
        .stdin(Stdio::inherit())
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit());

    let status = cmd.status()?;

    if !status.success() {
        return Err(anyhow::anyhow!(
            "Editor exited with non-zero status: {}",
            status.code().unwrap_or(-1)
        ));
    }

    Ok(())
}

/// Main function to get input from editor
pub fn get_editor_input(
    editor_cmd: &str,
    messages: &[&str],
    prefill: Option<&str>,
) -> Result<(String, bool)> {
    let temp_file = create_temp_file(messages, prefill)?;
    let temp_path = temp_file.path().to_path_buf();

    let symlink_path = PathBuf::from(".goose_prompt_temp.md");

View on GitHub (pinned to 3810898a74)

Solutions

  1. Re-open the editor and quit with a success status (vim :wq instead of :cq)
  2. Verify $EDITOR/$VISUAL resolves to an installed, working binary: echo $EDITOR && $EDITOR --version
  3. Use inline multi-line input instead of the editor in environments that cannot host one
  4. If the exit was an intentional abort, treat this error as a user cancellation at the call site instead of a hard failure

Example fix

// before
let text = get_editor_input(editor_cmd, &[])?;
// after
match get_editor_input(editor_cmd, &[]) {
    Ok(text) => { /* use text */ }
    Err(e) if e.to_string().contains("non-zero status") => return Ok(()), // user aborted
    Err(e) => return Err(e),
}
Defensive patterns

Strategy: try-catch

Validate before calling

use std::process::Command;

fn editor_works(editor_cmd: &str) -> bool {
    let mut parts = editor_cmd.split_whitespace();
    let bin = match parts.next() { Some(b) => b, None => return false };
    Command::new(bin).arg("--version").output().is_ok()
}

Try / catch

match get_editor_input(editor_cmd, &[]) {
    Ok(text) => { /* use text */ }
    Err(e) if e.to_string().contains("non-zero status") => {
        // editor aborted: treat as user cancellation, not a crash
        return Ok(());
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Any path that opens the editor for input (interactive CLI editor flow via get_editor_input / launch_editor) where the editor exits non-zero: quitting vim with :cq, an EDITOR wrapper script that exits 1, or an editor binary that crashes on startup.

Common situations: EDITOR/VISUAL pointing at a missing or broken binary; the user aborting the editor deliberately; containers/CI without a usable editor; terminal multiplexer issues breaking the spawned editor.

Related errors


AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16). Data as JSON: /api/errors/501368a3c4d53d54. Report an issue: GitHub.