jdx/mise · error

execute_external_command not implemented for {}

Error message

execute_external_command not implemented for {}

What it means

mise plugins expose custom CLI subcommands via `external_commands`; the default trait implementation returns an empty command list but a non-default `execute_external_command` that always panics with `unimplemented!`. Hitting this means the plugin's `external_commands()` advertised a command (or a caller invoked it directly) without the plugin providing a real execution implementation. It is a plugin-implementation bug or a race where the command list and dispatcher disagree.

Source

Thrown at src/plugins/mod.rs:372

        _dry_run: bool,
    ) -> eyre::Result<()> {
        Ok(())
    }
    async fn update(&self, _pr: &dyn SingleReport, _gitref: Option<String>) -> eyre::Result<()> {
        Ok(())
    }
    async fn uninstall(&self, _pr: &dyn SingleReport) -> eyre::Result<()> {
        Ok(())
    }
    async fn install(&self, _config: &Arc<Config>, _pr: &dyn SingleReport) -> eyre::Result<()> {
        Ok(())
    }
    fn external_commands(&self) -> eyre::Result<Vec<ExternalCommand>> {
        Ok(vec![])
    }
    #[cfg_attr(coverage_nightly, coverage(off))]
    fn execute_external_command(&self, _command: &str, _args: Vec<String>) -> eyre::Result<()> {
        unimplemented!(
            "execute_external_command not implemented for {}",
            self.name()
        )
    }
}

impl Ord for PluginEnum {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.name().cmp(other.name())
    }
}

impl PartialOrd for PluginEnum {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Use a supported command: run `mise <plugin> --help` or check the plugin's listed external commands before invoking.
  2. Update mise (`mise self-update`) — the plugin may have gained an implementation.
  3. Reinstall/update the plugin itself (e.g. `mise plugin update <name>`) so its command advertisement matches its executor.
  4. If it's your own plugin, override `execute_external_command` (and keep `external_commands()` in sync) in the trait impl.

Example fix

// before
fn external_commands(&self) -> eyre::Result<Vec<ExternalCommand>> {
    Ok(vec![ExternalCommand { name: "foo", .. }])
}
// execute_external_command left as default unimplemented!()

// after
fn execute_external_command(&self, command: &str, args: Vec<String>) -> eyre::Result<()> {
    match command {
        "foo" => self.run_foo(args),
        _ => unreachable!("only advertised commands reach here"),
    }
}
Defensive patterns

Strategy: validation

Validate before calling

# Shell: verify the command is advertised before invoking
mise <plugin> --help 2>/dev/null | grep -q "<command>" || { echo "command not supported by plugin"; exit 1; }

Try / catch

// Rust: guard against plugins without external command support
match plugin.external_commands() {
    Ok(cmds) if cmds.iter().any(|c| c.name == command) => plugin.execute_external_command(command, args)?,
    _ => eyre::bail!("plugin {} does not support command {}", plugin.name(), command),
}

Prevention

When it happens

Trigger: Invoking `mise <plugin> <command>` (e.g. `mise erlang something`) against a plugin whose backend trait impl does not override `execute_external_command`, or internal dispatch calling `execute_external_command` on a plugin that never advertised support.

Common situations: Running plugin-specific subcommands on core/builtin plugins that don't implement them, after a mise upgrade changed the plugin API surface, or with third-party plugins that advertise commands but inherit the default executor.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/901106e1acee6f33. Report an issue: GitHub.