Repository navigation
fix(exec): name installed-but-inactive tools on resolution failure - #11803
Conversation
`mise install <tool>` deliberately writes to no config file, so the tool's bin dir never joins the PATH `mise exec` builds. Resolution then fails legitimately -- but with no hint that mise had just installed the tool: `cannot find binary path` on Windows, a bare ENOENT on unix. Discussion jdx#11183 already fixed this shape for the shim dispatch path; this covers the remaining non-shim one. When an installed-but-unconfigured tool would have provided the bin, append what it is and how to reach it. Matching is by tool name, so `npm` from `node` is not recognized; those callers keep the existing message rather than getting a wrong one. Closes jdx#4407
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Central YAML (base), Organization UI (inherited) Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthrough
ChangesInactive tool execution diagnostics
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant MiseExec
participant ToolResolver
participant InstallState
User->>MiseExec: run inactive tool
MiseExec->>ToolResolver: resolve program through PATH
ToolResolver-->>MiseExec: resolution failure
MiseExec->>InstallState: check installed tools
InstallState-->>MiseExec: installed inactive tool
MiseExec-->>User: show mise use or mise exec guidance
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThe PR improves failed
Confidence Score: 5/5The PR appears safe to merge. The previously reported configured-tool misclassification is fixed, and no blocking failure remains. Important Files Changed
Reviews (3): Last reviewed commit: "fix(exec): treat a declared-but-unresolv..." | Re-trigger Greptile |
list_current_versions() drops a tool whose version failed to resolve, whose OS is unsupported, or whose backend could not be built, so the hint could tell a user that a tool sitting in their config file "is not in any config file". Check the toolset's declared keys instead, which survive all three. A disabled tool never reaches that check at all -- Toolset::add_version skips it -- so filter disabled tools out of the installed candidates too, where the same wrong advice would otherwise apply.
Closes #4407.
The report still reproduces
#4407 (Feb 2025, 5 👍, no replies) says
mise install ghreports success butghis then not runnable. That is still true today, on both platforms — thekey detail is that the reporter had no
ghof their own onPATH:Windows, v2026.8.2 windows-x64, isolated
MISE_DATA_DIR:Linux, v2026.8.3 linux-x64:
The install genuinely succeeded — the binary is on disk — and
mise execgenuinely cannot run it, because
mise installwrites to no config file andmise execbuilds itsPATHfrom the tools in the config. So the failure iscorrect. What is missing is any hint that mise itself put the tool there, or
that
mise use <tool>/mise exec <tool> -- <tool>is one word away.Since v2026.3.0
mise installdoes warn (installed but not activated — it is not in any config file), but that is printed at install time. The command thatactually fails, possibly much later, says nothing.
What this changes
Discussion #11183 already fixed exactly this shape for the shim dispatch
path —
err_shim_not_foundreplacedcannot find binary pathwith actionableguidance whenever
__MISE_SHIM_PATHis set. The non-shim path was left as-is.This covers it.
When a bin fails to resolve and an installed-but-unconfigured tool of that name
would have provided it, the existing error gains an explanation:
The original error line is kept and appended to, not replaced: it is correct,
and it is what users search for.
exec.rs): the two non-shim arms that returnedwhich::Error::CannotFindBinaryPathnow go through a helper that appends thehint when there is one.
exec.rs): theErr(_) => programfallback is deliberate —whichcan fail where
execstill succeeds — so the branch is untouched. A flagrecords that resolution failed, and the hint is appended to the
bail!thatruns only after
exechas definitively failed. No behaviour change, onlymessage.
install_state::try_list_tools()is added alongside the existingtry_list_plugins().list_tools()panics when install state was neverinitialized, which is not acceptable on an error path.
Limitation, deliberate
Matching is by tool name, reusing
BackendArg::matches_bin_name(whichalready handles the Windows
.exesuffix and case). Sogh,jq,usagearerecognized;
npmprovided bynodeis not. In that case the helper returnsNoneand the caller keeps today's message — no regression, just no hint.Resolving it properly would mean scanning every installed tool's bin dir, which
is too much for an error path.
The hint is also suppressed when a configured tool matches the bin: that
failure has a different cause, and
err_no_version_set/unavailable_configured_tool_messagealready explain it.Out of scope
sandbox-execbail!is a separate path and is not touched.mise installwarning is unchanged — it is already correct.tool_stub.rssharesexec_program, so it benefits without special-casing.Tests
shims.rscovering: the message names the tool, a configuredtool yields
None, and a bin that does not name its tool yieldsNone.e2e/cli/test_exec_inactive_installed_tool— installsdummywithoutactivating it, asserts the hint and that the suggested command works, and
asserts an unknown bin keeps the original error untouched.
e2e-win/exec_inactive_tool.Tests.ps1— same on Windows, usingusage. Itstrips any host
usagefromPATHfirst; a preinstalled copy would resolveand mask the failure (that is exactly the trap I fell into while measuring
this originally).
Existing assertions on
couldn't exec process/cannot find binary path(
e2e/config/test_auto_install_false,e2e/config/test_config_auto_install_disable_tools) all pass the tool on theexecline, so it is in the toolset and the hint is suppressed. They also matchby substring, so appended text could not break them either way.
I could not re-test the reporter's own v2025.2.4: that binary can no longer
install anything, as
https://mise-versions.jdx.dev/aqua-registry/cli/cli/registry.yamlnow returns 400.
Summary by CodeRabbit
New Features
mise execerrors when an installed tool is not activated.Tests