Skip to content

fix(shim): detect shims by checking shims directory instead of binary name#8694

Merged
jdx merged 4 commits intomainfrom
fix/shim-detection
Mar 22, 2026
Merged

fix(shim): detect shims by checking shims directory instead of binary name#8694
jdx merged 4 commits intomainfrom
fix/shim-detection

Conversation

@jdx
Copy link
Copy Markdown
Owner

@jdx jdx commented Mar 21, 2026

Summary

  • Shim detection now checks if a file matching argv[0]'s basename exists in the shims directory, instead of using is_mise_binary() which checked if the binary name started with "mise-"
  • This fixes the case where package managers name the binary mise-<version> (e.g. mise-2026.3.7), causing shims to be incorrectly identified as mise itself and arguments like -json to be parsed as mise's -j flag
  • Removes the now-unused is_mise_binary() function

Fixes #8641

Test plan

  • Added e2e/cli/test_shims_args test that verifies shim args (including -json which collides with mise's -j) are passed through
  • Existing test_shims and test_shims_fallback e2e tests pass

🤖 Generated with Claude Code


Note

Medium Risk
Changes shim detection logic that affects how mise decides whether to execute a tool vs parse its own CLI flags; regressions could break command invocation for renamed binaries or nonstandard shim setups.

Overview
Fixes shim detection by switching from binary-name prefix checks to verifying argv[0] exists in the shims directory (is_in_shims_dir()), and removes the now-unused is_mise_binary() helper.

Updates shim handling to rely on IS_RUNNING_AS_SHIM and adds an e2e regression test (e2e/cli/test_shims_args) to ensure shim-invoked tools receive flags like -json even when they collide with mise’s own options (e.g. -j/--jobs).

Written by Cursor Bugbot for commit 251ac24. This will update automatically on new commits. Configure here.

… name

Previously, shim detection used `is_mise_binary()` which checked if the
binary name started with "mise-". This broke when package managers named
the binary something like "mise-2026.3.7", causing the shim to be
incorrectly identified as a mise binary. Arguments like `-json` would
then be parsed as mise's `-j` flag instead of being passed through.

Now checks if a file matching argv[0]'s basename exists in the shims
directory, which is robust regardless of how the mise binary is named.

Fixes #8641

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the robustness of shim detection within the application. Previously, shim identification could be flawed when the main binary was renamed by package managers, leading to incorrect argument parsing. The updated logic now directly verifies the executable's presence in the designated shims directory, ensuring that shimmed tools correctly receive their intended arguments without interference from the application's own CLI flags.

Highlights

  • Improved Shim Detection: The method for detecting if a process is running as a shim has been updated to check if the executable's basename exists in the shims directory, rather than relying on the binary name's prefix.
  • Fix for Binary Naming Conflicts: This change resolves an issue where package managers renaming the mise binary (e.g., mise-2026.3.7) caused shims to be incorrectly identified as mise itself, leading to misinterpretation of command-line arguments like -json.
  • Code Refinement: The now-unused is_mise_binary() function has been removed, simplifying the codebase.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the shim detection logic to be more robust, especially for cases where mise is installed by package managers that rename the binary. The new approach checks for the existence of a file in the shims directory matching the executable name, which is a more reliable method. The changes look good and are supported by a new e2e test. I've added a few suggestions to refactor the new is_in_shims_dir function to make it a pure function, improving code clarity and avoiding repeated access to a global variable.

Comment thread src/env.rs

let bin_name = *MISE_BIN_NAME;
!is_mise_binary(bin_name)
crate::shims::is_in_shims_dir()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To make is_in_shims_dir a pure utility function, it's better to pass bin_name as an argument instead of accessing the global env::MISE_BIN_NAME within it. This change updates the call site here accordingly. This is part of a set of related suggestions.

Suggested change
crate::shims::is_in_shims_dir()
crate::shims::is_in_shims_dir(*MISE_BIN_NAME)

Comment thread src/shims.rs Outdated
Comment on lines +26 to +29
if !is_in_shims_dir() || cfg!(test) {
return Ok(());
}
let bin_name = *env::MISE_BIN_NAME;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To avoid multiple lookups of env::MISE_BIN_NAME, it can be fetched once and passed to the proposed pure version of is_in_shims_dir. This makes the data flow more explicit.

Suggested change
if !is_in_shims_dir() || cfg!(test) {
return Ok(());
}
let bin_name = *env::MISE_BIN_NAME;
let bin_name = *env::MISE_BIN_NAME;
if !is_in_shims_dir(bin_name) || cfg!(test) {
return Ok(());
}

Comment thread src/shims.rs
Comment on lines +601 to +606
pub fn is_in_shims_dir() -> bool {
let bin_name = *env::MISE_BIN_NAME;
let shim_path = dirs::SHIMS.join(bin_name);
// is_symlink() catches broken symlinks that .exists() would miss
shim_path.is_symlink() || shim_path.exists()
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To improve modularity and make this function's dependencies explicit, consider making it a pure function by accepting bin_name as an argument instead of accessing the global env::MISE_BIN_NAME.

pub fn is_in_shims_dir(bin_name: &str) -> bool {
    let shim_path = dirs::SHIMS.join(bin_name);
    // is_symlink() catches broken symlinks that .exists() would miss
    shim_path.is_symlink() || shim_path.exists()
}

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Mar 21, 2026

Greptile Summary

This PR fixes a shim-detection regression where package managers that name the mise binary mise-<version> (e.g. mise-2026.3.7) caused the binary to be incorrectly treated as a regular mise invocation because the old is_mise_binary() check matched the "mise-" prefix. The fix replaces that heuristic with a positive filesystem check: is_in_shims_dir() verifies that a file matching argv[0]'s basename actually exists in the configured shims directory, which is both more precise and more robust.

Key changes:

  • src/shims.rs: New is_in_shims_dir() function joins dirs::SHIMS with MISE_BIN_NAME and checks is_symlink() || exists() — the is_symlink() arm correctly handles broken shim symlinks that .exists() would miss.
  • src/env.rs: IS_RUNNING_AS_SHIM now calls is_in_shims_dir() instead of !is_mise_binary(). The now-unused is_mise_binary() helper is removed cleanly.
  • src/shims.rshandle_shim(): Guard updated to *env::MISE_TOOL_STUB || !*env::IS_RUNNING_AS_SHIM; the cfg!(test) early-return is handled inside the lazy, keeping test behaviour unchanged.
  • e2e/cli/test_shims_args: Regression test that exercises the -json flag (collides with mise's -j/--jobs flag) to confirm shim args are passed through unaltered.

Confidence Score: 5/5

  • Safe to merge — the fix is narrowly scoped, logically sound, and backed by a targeted regression test.
  • The change is small (three files, ~30 lines net), the new positive filesystem check is strictly more correct than the old name-prefix heuristic, all existing shim e2e tests continue to pass, and a new regression test directly exercises the reported failure mode. No correctness, security, or platform-compatibility issues were identified.
  • No files require special attention.

Important Files Changed

Filename Overview
src/shims.rs Adds is_in_shims_dir() which checks the shims directory for the running binary's filename (using `is_symlink()
src/env.rs Replaces the is_mise_binary() name-prefix heuristic with a direct call to shims::is_in_shims_dir() inside the IS_RUNNING_AS_SHIM lazy. The removed function is clean and unused after this change.
e2e/cli/test_shims_args New regression test that installs the dummy tool, reshims, and verifies that a flag colliding with mise's own CLI flag (-json → mise -j) is passed through to the tool. The dummy binary always exits 0 so assert_not_contains is safe to use here.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Process starts with argv0] --> B{cfg test?}
    B -- yes --> C[IS_RUNNING_AS_SHIM = false]
    B -- no --> D{MISE_TOOL_STUB?}
    D -- yes --> E[IS_RUNNING_AS_SHIM = true]
    D -- no --> F[is_in_shims_dir]
    F --> G{shims dir contains bin_name?}
    G -- yes --> H[IS_RUNNING_AS_SHIM = true]
    G -- no --> I[IS_RUNNING_AS_SHIM = false]

    C --> J[handle_shim]
    I --> J
    E --> J
    H --> J

    J --> K{MISE_TOOL_STUB OR NOT IS_RUNNING_AS_SHIM?}
    K -- yes --> L[Return early - direct mise or tool-stub path]
    K -- no --> M[Exec as shim - resolve tool binary and exec]
Loading

Last reviewed commit: "fix(shim): skip shim..."

Comment thread e2e/cli/test_shims_args Outdated
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Comment thread src/shims.rs
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 21, 2026

Hyperfine Performance

mise x -- echo

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.3.10 x -- echo 24.3 ± 0.7 23.2 28.8 1.00
mise x -- echo 24.3 ± 0.8 23.4 32.2 1.00 ± 0.04

mise env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.3.10 env 24.0 ± 1.0 22.7 29.6 1.00 ± 0.05
mise env 23.9 ± 0.5 23.0 27.4 1.00

mise hook-env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.3.10 hook-env 24.4 ± 0.6 23.4 27.2 1.00
mise hook-env 24.6 ± 0.8 23.7 35.7 1.01 ± 0.04

mise ls

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.3.10 ls 23.4 ± 0.6 22.6 26.8 1.00
mise ls 23.7 ± 0.7 22.7 28.0 1.01 ± 0.04

xtasks/test/perf

Command mise-2026.3.10 mise Variance
install (cached) 152ms 151ms +0%
ls (cached) 84ms 83ms +1%
bin-paths (cached) 88ms 86ms +2%
task-ls (cached) 823ms 837ms -1%

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Comment thread src/shims.rs
MISE_TOOL_STUB causes IS_RUNNING_AS_SHIM to be true, but tool stubs
should not go through handle_shim() since argv[0] is "mise", not a
shim name. Add an explicit guard to prevent infinite recursion.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@jdx jdx merged commit cfcb555 into main Mar 22, 2026
36 checks passed
@jdx jdx deleted the fix/shim-detection branch March 22, 2026 05:59
mise-en-dev added a commit that referenced this pull request Mar 22, 2026
### 🚀 Features

- **(github)** read tokens from gh CLI hosts.yml config by @jdx in
[#8692](#8692)
- **(task)** support optional `args` and `env` fields in `run` entries
by @jdx in [#8687](#8687)
- **(task)** add --skip-tools flag to mise run by @jdx in
[#8699](#8699)
- **(vfox)** add try_get, try_head, try_download_file to Lua HTTP module
by @jdx in [#8697](#8697)

### 🐛 Bug Fixes

- **(config)** recognize SSH and other non-HTTPS URLs in get_repo_url by
@modestman in [#8666](#8666)
- **(docs)** add dark mode support to favicon by @jdx in
[#8678](#8678)
- **(env)** support multiple --env/-E flags by @jdx in
[#8686](#8686)
- **(github)** rename_exe renames correct binary when archive contains
multiple executables by @jdx in
[#8700](#8700)
- **(implode)** include system data dir in implode cleanup by @jdx in
[#8696](#8696)
- **(install)** skip GitHub API calls for aqua tools in --locked mode by
@jdx in [#8679](#8679)
- **(install)** skip redundant provenance verification when lockfile has
integrity data by @jdx in [#8688](#8688)
- **(lock)** respect existing platforms in lockfile when running `mise
lock` by @jdx in [#8708](#8708)
- **(lock)** skip global config lockfile by default by @jdx in
[#8707](#8707)
- **(node)** expand tilde in default_packages_file path by @jdx in
[#8709](#8709)
- **(shell)** error when no version specified instead of silent no-op by
@jdx in [#8693](#8693)
- **(shim)** detect shims by checking shims directory instead of binary
name by @jdx in [#8694](#8694)
- **(task)** inherit task_config.dir for included TOML and file tasks by
@jdx in [#8689](#8689)
- **(task)** strip inline args when validating run.tasks references by
@jdx in [#8701](#8701)
- **(task)** include idiomatic version files in monorepo task toolset by
@jdx in [#8702](#8702)
- **(task)** improve error message when task files are not executable by
@jdx in [#8705](#8705)
- **(test)** update vfox provenance test for checksum-backed skip by
@jdx in [#8703](#8703)
- improve usage spec element support in tasks by @nkakouros in
[#8623](#8623)
- make env plugin (Module) vars available in Tera template context by
@victor-founder in [#8682](#8682)
- respect MISE_COLOR=0 for color_eyre error output by @jdx in
[#8690](#8690)
- add windows support for usage tool registry by @jdx in
[#8713](#8713)

### 📚 Documentation

- **(task)** clarify interactive task blocking behavior by @jdx in
[#8685](#8685)
- improve visibility of install_before setting by @jdx in
[#8712](#8712)

### 📦 Registry

- add rtk ([github:rtk-ai/rtk](https://github.com/rtk-ai/rtk)) by
@bricelalu in [#8683](#8683)

### New Contributors

- @victor-founder made their first contribution in
[#8682](#8682)
- @modestman made their first contribution in
[#8666](#8666)
- @bricelalu made their first contribution in
[#8683](#8683)
Comment thread e2e/cli/test_shims_args
Comment on lines +1 to +20
#!/usr/bin/env bash

# Regression test: shim must pass through flags like "-j" that overlap with
# mise's own CLI flags (e.g. --jobs / -j). See:
# https://github.com/jdx/mise/discussions/8641

export PATH="$MISE_DATA_DIR/shims:$PATH"

mise use -g dummy@1.0.0
mise reshim

# The dummy shim should execute the underlying tool, not mise itself.
# If shim detection is broken, mise would try to parse these as its own args.
assert_contains "dummy hello world" "This is Dummy 1.0.0!"
assert_not_contains "dummy" "mise manages dev tools"

# Verify that flags which collide with mise flags are passed through to the tool.
# -j is mise's --jobs flag; if the shim is not detected, mise parses "-json" as
# "-j son" and errors with "invalid value 'son' for '--jobs'".
assert_contains "dummy -json foo" "This is Dummy 1.0.0!"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did anyone ever see this regression test fail with the original code?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants