jdx/mise · error

failed to open the editor

Error message

failed to open the editor `{program}`: {err}
Set $EDITOR or $VISUAL to an editor mise can run.

What it means

`mise editor` (and commands spawning an editor) failed to launch the chosen editor program. The error names the program and points at $EDITOR/$VISUAL because the default editor name is typically the one missing from PATH.

Solutions

  1. Set $EDITOR or $VISUAL to an installed editor (e.g. export EDITOR=vim or code --wait)
  2. Install the editor the variable names, or fix the PATH so it is found
  3. Verify with `command -v "$EDITOR"` that the program resolves

Example fix

// before
mise editor        # EDITOR unset, no default editor on PATH
// after
export EDITOR="code --wait"
mise editor
Defensive patterns

Strategy: fallback

Validate before calling

command -v "${EDITOR:-vi}" >/dev/null || echo 'editor missing'

Prevention

When it happens

Trigger: crate::cmd::cmd(&program, args).run() returns Err — the editor binary does not exist or cannot be exec'd — most often when $EDITOR/$VISUAL is unset and the fallback program (e.g. an editor not installed) cannot start.

Common situations: Running mise in a minimal container or CI where no editor is installed; $EDITOR set to a non-existent binary; PATH missing the editor directory.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/08b6cf4a2dd1c4c6. Report an issue: GitHub.

Appendix: source

Thrown at src/cli/editor.rs:23

/// Open `file` in the user's editor and wait for it to exit.
///
/// The wait is part of the contract, not an accident of blocking IO: `mise dot edit --apply`
/// converges the target as soon as this returns, so an editor that detached would apply a file the
/// user had not saved yet.
pub(super) fn open_in_editor(file: &Path) -> Result<()> {
    open_in_editor_with(&crate::env::EDITOR, file)
}

/// Takes the editor rather than reading it, so the failure path can be driven from a test.
fn open_in_editor_with(editor: &str, file: &Path) -> Result<()> {
    let (program, mut args) = split_editor_command(editor)?;
    args.push(file.as_os_str().into());
    if let Err(err) = crate::cmd::cmd(&program, args).run() {
        // Name the program and the variables that choose it. A child that never starts comes back
        // as std's bare "program not found" (see the note in `backend::which_spawnable`), which
        // says neither what mise tried to run nor where the name came from — and the default is
        // the name most likely to be missing.
        bail!(
            "failed to open the editor `{program}`: {err}\n\
             Set $EDITOR or $VISUAL to an editor mise can run."
        );
    }
    Ok(())
}

fn split_editor_command(editor: &str) -> Result<(String, Vec<OsString>)> {
    let mut parts = shell_words::split(editor)
        .map_err(|e| eyre!("failed to parse EDITOR/VISUAL value {:?}: {}", editor, e))?
        .into_iter();
    let program = parts
        .next()
        .ok_or_else(|| eyre!("EDITOR/VISUAL is empty"))?;

    Ok((program, parts.map(Into::into).collect()))
}

View on GitHub (pinned to 533346cc37)