sigoden/aichat · error

The command ` ` exited with non-zero.

Error message

The command `{cmd_eval}` exited with non-zero.

What it means

In the branch of run_loader_command where the command writes output to a file, a non-zero exit status produces this bail (stderr is not captured in this path). The message tells you which command failed but not why.

Solutions

  1. Re-run the same command manually and check its exit code/stderr
  2. Fix the loader's arguments or input so it exits 0
  3. Ensure the output path is writable and the loader can create the file
  4. Check that required env vars for the loader are set in the spawning environment

Example fix

// before: failing flags
loader = ["pandoc", "--bad-flag"]
// after
loader = ["pandoc", "-f", "html", "-t", "markdown"]
Defensive patterns

Strategy: try-catch

Validate before calling

// smoke-test the command with the same args and check exit code
const r = spawnSync(cmd, args, { stdio: 'ignore' });
if (r.status !== 0) console.error(`${cmd} exits ${r.status}`);

Try / catch

try {
  const contents = await loadFromCommand(cmd, args);
} catch (e) {
  if (e.message.includes('exited with non-zero')) {
    // re-run manually for stderr since this path hides it
  }
}

Prevention

When it happens

Trigger: A loader command configured to write to an output file exits with status != 0 during load_with_command / load_protocol_path / fetch_with_loaders.

Common situations: Loader crashes or rejects the input silently; command not found behaviors handled earlier but other failures (bad flags, permissions) exit non-zero; environment differences between interactive shell and spawned process.

Understand the failure class

Background: "git command failed": what it means when a tool shells out to git and git exits non-zero — this error's family across 21 libraries.

Related errors


AI-assisted analysis of sigoden/aichat@82976d349a (2026-09-09). Data as JSON: /api/errors/3b267937235b4368. Report an issue: GitHub.

Appendix: source

Thrown at src/utils/command.rs:149

        let (success, stdout, stderr) =
            run_command_with_output(cmd, args, None).with_context(|| {
                format!("Unable to run `{cmd_eval}`, Perhaps '{cmd}' is not installed?")
            })?;
        if !success {
            let err = if !stderr.is_empty() {
                stderr
            } else {
                format!("The command `{cmd_eval}` exited with non-zero.")
            };
            bail!("{err}")
        }
        Ok(stdout)
    } else {
        let status = run_command(cmd, args, None).with_context(|| {
            format!("Unable to run `{cmd_eval}`, Perhaps '{cmd}' is not installed?")
        })?;
        if status != 0 {
            bail!("The command `{cmd_eval}` exited with non-zero.")
        }
        let contents = std::fs::read_to_string(&outpath)
            .context("Failed to read file generated by the loader")?;
        Ok(contents)
    }
}

pub fn edit_file(editor: &str, path: &Path) -> Result<()> {
    let mut child = Command::new(editor).arg(path).spawn()?;
    child.wait()?;
    Ok(())
}

pub fn append_to_shell_history(shell: &str, command: &str, exit_code: i32) -> io::Result<()> {
    if let Some(history_file) = get_history_file(shell) {
        let command = command.replace('\n', " ");
        let now = now_timestamp();
        let history_txt = if shell == "fish" {

View on GitHub (pinned to 82976d349a)