jdx/mise · error · eyre::Report

install_command cannot be used with filter_bins

Error message

install_command cannot be used with filter_bins

What it means

The spm backend treats `install_command` (full custom install) and `filter_bins` (post-build bin filtering) as mutually exclusive, because a custom command controls the whole install layout and filter_bins only makes sense against the default swift build output. source_install_command bails when both are set.

Source

Thrown at src/backend/spm.rs:154

    fn install_command(&self) -> eyre::Result<Option<String>> {
        let Some(value) = self.values.raw().opts.get("install_command") else {
            return Ok(None);
        };
        let Some(command) = value.as_str() else {
            bail!("install_command must be a non-empty string");
        };
        let command = command.trim();
        if command.is_empty() {
            bail!("install_command must be a non-empty string");
        }
        Ok(Some(command.to_string()))
    }

    fn source_install_command(&self) -> eyre::Result<Option<String>> {
        let command = self.install_command()?;
        if command.is_some() && self.filter_bins().is_some() {
            bail!("install_command cannot be used with filter_bins");
        }
        Ok(command)
    }
}

#[async_trait]
impl Backend for SPMBackend {
    fn get_type(&self) -> BackendType {
        BackendType::Spm
    }

    fn ba(&self) -> &Arc<BackendArg> {
        &self.ba
    }

    fn get_dependencies(&self) -> eyre::Result<Vec<&str>> {
        Ok(vec!["swift"])
    }

View on GitHub (pinned to 6f52dcdf99)

Solutions

  1. Remove `filter_bins` and let install_command fully own the output (it should place executables in the install path's bin/)
  2. Remove `install_command` and use the default swift build plus `filter_bins`
  3. If the command only renames binaries, drop it and use `bin = ...` / rename options instead

Example fix

# before
[tools."spm:foo/bar"]
version = "1.0.0"
install_command = "make install PREFIX=$MISE_TOOL_INSTALL_PATH"
filter_bins = "bar"

# after
[tools."spm:foo/bar"]
version = "1.0.0"
install_command = "make install PREFIX=$MISE_TOOL_INSTALL_PATH"
Defensive patterns

Strategy: validation

Validate before calling

entry=$(tomlq -r '.tools["spm:foo/bar"]' mise.toml 2>/dev/null); echo "$entry" | grep -q 'install_command' && echo "$entry" | grep -q 'filter_bins' && echo 'conflict: pick one'

Type guard

fn compatible_spm_opts(opts: &toml::Value) -> bool {
    let m = opts.as_table().unwrap_or(&Default::default());
    !(m.contains_key("install_command") && m.contains_key("filter_bins"))
}

Prevention

When it happens

Trigger: A tool entry that sets both `install_command = "./install.sh"` and `filter_bins = "mybin"`. The conflict is checked whenever a custom install command is present.

Common situations: Incrementally adding filter_bins to an entry that already uses install_command, or copying options from two working examples into one tool block.

Related errors


AI-assisted analysis of jdx/mise@6f52dcdf99 (2026-08-22). Data as JSON: /api/errors/242b217b7ea7ed5e. Report an issue: GitHub.