{"record":{"id":"242b217b7ea7ed5e","repo":"jdx/mise","slug":"install-command-cannot-be-used-with-filter-bins","errorCode":null,"errorMessage":"install_command cannot be used with filter_bins","messagePattern":"install_command cannot be used with filter_bins","errorType":"validation","errorClass":"eyre::Report","httpStatus":null,"severity":"error","filePath":"src/backend/spm.rs","lineNumber":154,"sourceCode":"\n    fn install_command(&self) -> eyre::Result<Option<String>> {\n        let Some(value) = self.values.raw().opts.get(\"install_command\") else {\n            return Ok(None);\n        };\n        let Some(command) = value.as_str() else {\n            bail!(\"install_command must be a non-empty string\");\n        };\n        let command = command.trim();\n        if command.is_empty() {\n            bail!(\"install_command must be a non-empty string\");\n        }\n        Ok(Some(command.to_string()))\n    }\n\n    fn source_install_command(&self) -> eyre::Result<Option<String>> {\n        let command = self.install_command()?;\n        if command.is_some() && self.filter_bins().is_some() {\n            bail!(\"install_command cannot be used with filter_bins\");\n        }\n        Ok(command)\n    }\n}\n\n#[async_trait]\nimpl Backend for SPMBackend {\n    fn get_type(&self) -> BackendType {\n        BackendType::Spm\n    }\n\n    fn ba(&self) -> &Arc<BackendArg> {\n        &self.ba\n    }\n\n    fn get_dependencies(&self) -> eyre::Result<Vec<&str>> {\n        Ok(vec![\"swift\"])\n    }","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/jdx/mise/blob/6f52dcdf99e282ef7a7db68c81301fa4618d0f79/src/backend/spm.rs#L136-L172","documentation":"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.","triggerScenarios":"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.","commonSituations":"Incrementally adding filter_bins to an entry that already uses install_command, or copying options from two working examples into one tool block.","solutions":["Remove `filter_bins` and let install_command fully own the output (it should place executables in the install path's bin/)","Remove `install_command` and use the default swift build plus `filter_bins`","If the command only renames binaries, drop it and use `bin = ...` / rename options instead"],"exampleFix":"# before\n[tools.\"spm:foo/bar\"]\nversion = \"1.0.0\"\ninstall_command = \"make install PREFIX=$MISE_TOOL_INSTALL_PATH\"\nfilter_bins = \"bar\"\n\n# after\n[tools.\"spm:foo/bar\"]\nversion = \"1.0.0\"\ninstall_command = \"make install PREFIX=$MISE_TOOL_INSTALL_PATH\"","handlingStrategy":"validation","validationCode":"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'","typeGuard":"fn compatible_spm_opts(opts: &toml::Value) -> bool {\n    let m = opts.as_table().unwrap_or(&Default::default());\n    !(m.contains_key(\"install_command\") && m.contains_key(\"filter_bins\"))\n}","tryCatchPattern":null,"preventionTips":["install_command owns the whole install; filter_bins owns post-build filtering — never both","When adding options to an existing tool block, re-read which ones are mutually exclusive"],"tags":["spm","swift","config-validation","conflicting-options","mise-toml"],"backgroundTag":"conflicting-config-options","analyzedSha":"6f52dcdf99e282ef7a7db68c81301fa4618d0f79","analyzedAt":"2026-08-22T10:14:23.840Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}