Skip to content

fix(exec): respect PATH order for virtualenv resolution in mise x#8342

Merged
jdx merged 3 commits intomainfrom
fix/exec-venv-bypass
Feb 25, 2026
Merged

fix(exec): respect PATH order for virtualenv resolution in mise x#8342
jdx merged 3 commits intomainfrom
fix/exec-venv-bypass

Conversation

@jdx
Copy link
Owner

@jdx jdx commented Feb 25, 2026

Summary

Root Cause

PR #8276 added two fixes for infinite recursion:

  1. Strip shims from PATH in exec_program — prevents shim recursion (kept)
  2. Pre-resolve bare program names via which_bin — prevents wrapper script recursion (removed)

Fix #2 resolves e.g. python~/.local/share/mise/installs/python/3.9.1/bin/python before PATH is computed. Since the result is an absolute path, exec_program skips PATH lookup entirely, so .venv/bin/python (added by _.python.venv) is never found.

Fixes #8340

Test plan

  • cargo check — no warnings
  • mise run test:e2e test_exec — all exec e2e tests pass
  • test_exec_shim_recursion still passes (shim stripping in exec_program handles this)

🤖 Generated with Claude Code


Note

Medium Risk
Changes how mise x resolves executables, which can alter which binary runs in edge PATH setups. Added E2E tests reduce regression risk, but behavior changes could impact users relying on the old forced mise-path resolution.

Overview
mise x no longer pre-resolves bare command names to a mise-managed tool path via Toolset::which_bin in Exec::run, allowing normal PATH lookup to pick up higher-precedence overrides like virtualenv binaries.

Adds two E2E regression tests: one ensuring PATH-prepended “venv” bins win over mise installs during mise x, and another ensuring a PATH-preceding wrapper that re-invokes mise x doesn’t hang (infinite recursion) and still executes the real tool.

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

Remove the `which_bin` pre-resolution that was introduced in #8276 to
prevent wrapper script recursion. This pre-resolution bypasses PATH
entirely for mise-managed tools, breaking `_.python.venv` and similar
configs where a virtualenv binary should take precedence over the
mise-managed install.

The shim stripping in `exec_program` (also from #8276) already prevents
the main recursion vector (shims in PATH). The wrapper script edge case
should not be solved by bypassing PATH for all programs.

Fixes #8340

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @jdx, 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 resolves a regression where mise x commands would bypass the PATH environment variable's order, specifically impacting virtual environment resolution. By removing a pre-resolution step, the system now correctly prioritizes binaries found earlier in the PATH, ensuring that tools like Python virtualenvs function as expected without reintroducing shim recursion issues.

Highlights

  • Removed pre-resolution logic: The ts.which_bin() pre-resolution from Exec::run() that was introduced in fix(exec): strip shims from PATH on Unix to prevent infinite recursion #8276 has been removed.
  • Restored PATH order for virtualenvs: This change ensures that the PATH order is respected, allowing virtualenv binaries (e.g., from _.python.venv configurations) to take precedence over mise-managed installations.
  • Addressed regression: The previous pre-resolution bypassed PATH entirely for mise-managed tools, causing issues with virtualenv resolution, which this PR rectifies.
  • Maintained shim recursion prevention: The shim stripping in exec_program (also from fix(exec): strip shims from PATH on Unix to prevent infinite recursion #8276) remains in place, continuing to prevent shim recursion without the need for the problematic pre-resolution.
Changelog
  • src/cli/exec.rs
    • Removed a conditional block that pre-resolved program paths on Unix systems, which was causing PATH order to be ignored for mise-managed tools.
Activity
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.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

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.

Regression test that verifies `mise x -- tool` respects PATH order when
a virtualenv-like directory is prepended via mise config. Fails without
the accompanying fix due to `which_bin` pre-resolution bypassing PATH.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
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 addresses an issue where mise x would not respect the PATH order for virtualenv resolution. The change removes a block of code responsible for pre-resolving program paths, which was causing this issue by bypassing the standard PATH lookup. The original purpose of the removed code, preventing shim recursion, is now handled by a different mechanism that remains in place. The change is correct and well-justified, fixing the described bug without reintroducing the recursion problem.

@greptile-apps
Copy link

greptile-apps bot commented Feb 25, 2026

Greptile Summary

This PR removes the ts.which_bin() pre-resolution that was introduced in #8276, which was bypassing PATH lookup and preventing virtualenv binaries from taking precedence over mise-managed tools.

Key changes:

  • Removed the which_bin pre-resolution logic from Exec::run() that resolved bare program names to absolute mise-managed tool paths before PATH computation
  • This allows exec_program to properly resolve binaries via the full PATH (which includes .venv/bin when _.python.venv is configured)
  • Recursion protection remains intact via shim-stripping in exec_program, which was the other fix from fix(exec): strip shims from PATH on Unix to prevent infinite recursion #8276
  • Added regression test test_exec_venv_path_order to verify venv binaries are found first

Rationale:
When which_bin pre-resolved python to ~/.local/share/mise/installs/python/3.9.1/bin/python, the absolute path skipped PATH lookup entirely, so .venv/bin/python added by _.python.venv was never considered. The fix correctly delegates all PATH resolution to exec_program where shims are stripped.

Confidence Score: 4/5

  • This PR is safe to merge with low risk, though it changes execution resolution behavior
  • The change correctly reverts problematic pre-resolution logic while keeping the essential shim-stripping recursion protection. The test suite covers both the new venv PATH order case and the original shim recursion case. The only risk is potential edge cases with wrapper scripts that aren't covered by shim-stripping alone, but the PR description indicates this was already tested.
  • No files require special attention - the logic is straightforward and well-tested

Important Files Changed

Filename Overview
src/cli/exec.rs Removes which_bin pre-resolution that bypassed PATH lookup, restoring correct virtualenv precedence
e2e/cli/test_exec_venv_path_order Adds regression test verifying venv binaries are found before mise-managed tools when prepended to PATH

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    Start["`mise x -- python`"] --> ParseCmd["Parse command"]
    ParseCmd --> BuildEnv["Build env with PATH<br/>(includes .venv/bin if configured)"]
    BuildEnv --> ExecProg["exec_program(program, args, env)"]
    
    ExecProg --> CheckPath{Is program<br/>already a path?}
    CheckPath -->|Yes, contains /| UseAsIs["Use as-is"]
    CheckPath -->|No, bare name| StripShims["Strip shims from PATH"]
    
    StripShims --> WhichIn["which_in(program, filtered_path)"]
    WhichIn --> Found{Found?}
    Found -->|Yes| ResolvedPath["Use resolved path<br/>(e.g., .venv/bin/python)"]
    Found -->|No| Fallback["Fall back to original"]
    
    UseAsIs --> Exec["execvp()"]
    ResolvedPath --> Exec
    Fallback --> Exec
    
    style StripShims fill:#90EE90
    style WhichIn fill:#87CEEB
    style ResolvedPath fill:#FFD700
Loading

Last reviewed commit: d85ede1

Copy link

@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.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

@github-actions
Copy link

github-actions bot commented Feb 25, 2026

Hyperfine Performance

mise x -- echo

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.20 x -- echo 26.3 ± 0.9 24.3 32.9 1.00
mise x -- echo 26.7 ± 1.0 23.9 29.6 1.01 ± 0.05

mise env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.20 env 25.3 ± 0.9 23.2 29.6 1.00
mise env 25.6 ± 0.9 23.3 28.7 1.01 ± 0.05

mise hook-env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.20 hook-env 25.2 ± 0.8 23.3 28.3 1.00
mise hook-env 26.6 ± 1.1 24.1 31.1 1.05 ± 0.05

mise ls

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.20 ls 23.5 ± 0.9 21.4 28.4 1.00
mise ls 24.6 ± 1.0 21.6 29.0 1.05 ± 0.06

xtasks/test/perf

Command mise-2026.2.20 mise Variance
install (cached) 154ms 154ms +0%
ls (cached) 85ms 86ms -1%
bin-paths (cached) 90ms 90ms +0%
task-ls (cached) 827ms 832ms +0%

Addresses Cursor Bugbot feedback on PR #8342. Simulates the
.devcontainer/bin/tool scenario from #8276 where a wrapper script that
calls `mise x -- tool` sits before mise tool paths in the system PATH.

The test passes because `exec_program` resolves programs via the
mise-computed PATH (where tool install paths are prepended before the
original system PATH), so the real binary is found before the wrapper.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@greptile-apps
Copy link

greptile-apps bot commented Feb 25, 2026

Greptile Summary

Reverts the ts.which_bin() pre-resolution introduced in PR #8276, which was breaking virtualenv PATH precedence by resolving bare tool names to absolute mise-managed paths before PATH computation.

  • Removed Unix-only pre-resolution logic that bypassed PATH lookup for mise-managed tools
  • The shim stripping mechanism in exec_program (kept from fix(exec): strip shims from PATH on Unix to prevent infinite recursion #8276) is sufficient to prevent both shim and wrapper script recursion
  • When mise x runs, env_with_path prepends mise tool paths to PATH, ensuring mise-managed tools are found before wrapper scripts
  • Added comprehensive regression tests for both the venv PATH ordering (fixed by this PR) and wrapper recursion (still prevented)

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The change cleanly reverts problematic pre-resolution logic while preserving the shim stripping that prevents recursion. Both regression tests pass (venv PATH order and wrapper recursion), and the fix directly addresses the root cause of issue Bug: `mise x -- python` bypasses virtualenv after v2026.2.18 #8340 without introducing new complexity
  • No files require special attention

Important Files Changed

Filename Overview
src/cli/exec.rs Removes Unix-specific pre-resolution that bypassed PATH, restoring correct virtualenv precedence
e2e/cli/test_exec_venv_path_order Adds regression test validating that virtualenv binaries take precedence over mise-managed tools
e2e/cli/test_exec_wrapper_recursion Adds regression test proving shim stripping prevents wrapper script recursion without pre-resolution

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[User runs: mise x -- python] --> B[Exec::run parses command]
    B --> C[Build toolset with mise config]
    C --> D[Install missing tools if needed]
    D --> E[Compute env_with_path]
    E --> F{PATH construction}
    F --> G[Prepend mise tool paths]
    G --> H[Add _.path entries like .venv/bin]
    H --> I[Add original PATH]
    I --> J[exec_program called with bare 'python']
    J --> K{Is program already absolute path?}
    K -->|Yes| L[Use as-is]
    K -->|No| M[Filter shims from PATH]
    M --> N[Use which_in to resolve]
    N --> O{Which binary found first?}
    O -->|.venv/bin/python| P[Execute venv python]
    O -->|mise python| Q[Execute mise python]
    O -->|wrapper script| R[Wrapper calls mise x again]
    R --> S[Recursive call prepends mise paths again]
    S --> T[Mise python found before wrapper]
    T --> Q
Loading

Last reviewed commit: b241665

@jdx jdx enabled auto-merge (squash) February 25, 2026 12:35
@jdx jdx merged commit 46f94c1 into main Feb 25, 2026
36 checks passed
@jdx jdx deleted the fix/exec-venv-bypass branch February 25, 2026 12:35
mise-en-dev added a commit that referenced this pull request Feb 26, 2026
### 🐛 Bug Fixes

- **(exec)** respect PATH order for virtualenv resolution in mise x by
@jdx in [#8342](#8342)
- **(task)** revert process group changes that cause hangs with nested
mise tasks by @jdx in [#8347](#8347)
- **(task)** resolve vars from subdirectory configs for monorepo tasks
by @jdx in [#8343](#8343)
- **(task)** resolve dependencies before prepare to fix monorepo glob
deps by @jdx in [#8353](#8353)
- python noarch with Conda backend by @wolfv in
[#8349](#8349)

### New Contributors

- @wolfv made their first contribution in
[#8349](#8349)

## 📦 Aqua Registry Updates

#### New Packages (3)

- [`alexhallam/tv`](https://github.com/alexhallam/tv)
- [`arcanist-sh/hx`](https://github.com/arcanist-sh/hx)
- [`dathere/qsv`](https://github.com/dathere/qsv)

#### Updated Packages (3)

- [`astral-sh/ruff`](https://github.com/astral-sh/ruff)
- [`caarlos0/fork-cleaner`](https://github.com/caarlos0/fork-cleaner)
- [`rhysd/actionlint`](https://github.com/rhysd/actionlint)
risu729 pushed a commit to risu729/mise that referenced this pull request Feb 27, 2026
…x#8342)

## Summary

- Remove the `ts.which_bin()` pre-resolution from `Exec::run()` that was
introduced in jdx#8276
- This pre-resolution bypassed PATH entirely for mise-managed tools,
breaking `_.python.venv` and similar configs where a virtualenv binary
should take precedence over the mise-managed install
- The shim stripping in `exec_program` (also from jdx#8276) already
prevents shim recursion, which was the primary problem that PR solved

## Root Cause

PR jdx#8276 added two fixes for infinite recursion:
1. Strip shims from PATH in `exec_program` — prevents shim recursion
(**kept**)
2. Pre-resolve bare program names via `which_bin` — prevents wrapper
script recursion (**removed**)

Fix #2 resolves e.g. `python` →
`~/.local/share/mise/installs/python/3.9.1/bin/python` before PATH is
computed. Since the result is an absolute path, `exec_program` skips
PATH lookup entirely, so `.venv/bin/python` (added by `_.python.venv`)
is never found.

Fixes jdx#8340

## Test plan

- [x] `cargo check` — no warnings
- [x] `mise run test:e2e test_exec` — all exec e2e tests pass
- [x] `test_exec_shim_recursion` still passes (shim stripping in
`exec_program` handles this)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes how `mise x` resolves executables, which can alter which
binary runs in edge PATH setups. Added E2E tests reduce regression risk,
but behavior changes could impact users relying on the old forced
mise-path resolution.
> 
> **Overview**
> `mise x` no longer pre-resolves bare command names to a mise-managed
tool path via `Toolset::which_bin` in `Exec::run`, allowing normal PATH
lookup to pick up higher-precedence overrides like virtualenv binaries.
> 
> Adds two E2E regression tests: one ensuring PATH-prepended “venv” bins
win over mise installs during `mise x`, and another ensuring a
PATH-preceding wrapper that re-invokes `mise x` doesn’t hang (infinite
recursion) and still executes the real tool.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
b241665. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
risu729 pushed a commit to risu729/mise that referenced this pull request Feb 27, 2026
### 🐛 Bug Fixes

- **(exec)** respect PATH order for virtualenv resolution in mise x by
@jdx in [jdx#8342](jdx#8342)
- **(task)** revert process group changes that cause hangs with nested
mise tasks by @jdx in [jdx#8347](jdx#8347)
- **(task)** resolve vars from subdirectory configs for monorepo tasks
by @jdx in [jdx#8343](jdx#8343)
- **(task)** resolve dependencies before prepare to fix monorepo glob
deps by @jdx in [jdx#8353](jdx#8353)
- python noarch with Conda backend by @wolfv in
[jdx#8349](jdx#8349)

### New Contributors

- @wolfv made their first contribution in
[jdx#8349](jdx#8349)

## 📦 Aqua Registry Updates

#### New Packages (3)

- [`alexhallam/tv`](https://github.com/alexhallam/tv)
- [`arcanist-sh/hx`](https://github.com/arcanist-sh/hx)
- [`dathere/qsv`](https://github.com/dathere/qsv)

#### Updated Packages (3)

- [`astral-sh/ruff`](https://github.com/astral-sh/ruff)
- [`caarlos0/fork-cleaner`](https://github.com/caarlos0/fork-cleaner)
- [`rhysd/actionlint`](https://github.com/rhysd/actionlint)
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.

1 participant