fix(env): preserve user-configured PATH entries from env._.path#6835
fix(env): preserve user-configured PATH entries from env._.path#6835
Conversation
Fixes a regression introduced in f4dca1b where user-configured paths from env._.path were being filtered out if they already existed in __MISE_ORIG_PATH. This caused incorrect PATH ordering when users explicitly configured paths to ensure precedence. ## Problem When a user configured env._.path to prepend a directory that was already in their original PATH (e.g., /opt/homebrew/bin), the filtering logic would remove it, breaking the user's intended PATH ordering. Example: - Original PATH: /usr/bin:/opt/homebrew/bin - User configures: env._.path = ["/opt/homebrew/bin"] - Expected: /opt/homebrew/bin:/usr/bin:/opt/homebrew/bin - Actual (bug): /usr/bin:/opt/homebrew/bin ## Solution Separate path handling into two categories: 1. User-configured paths (from env._.path) - never filtered, always prepended 2. Tool installation paths - filtered if they duplicate original PATH entries Added list_final_paths_split() to return paths separately, and updated build_path_operations() to only filter tool paths while preserving user-configured paths. ## Changes - src/toolset/mod.rs: Add list_final_paths_split() method - src/cli/hook_env.rs: Update build_path_operations() to handle paths separately - e2e/config/test_env_path_ordering: Add regression test 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Pull Request Overview
This PR fixes a regression where user-configured paths from env._.path were being incorrectly filtered out when they already existed in the original PATH, breaking intended PATH ordering for explicit user configurations.
- Separates path handling into user-configured paths (never filtered) and tool installation paths (filtered for duplicates)
- Updates path building logic to preserve user-specified ordering while maintaining the existing duplicate filtering for tool paths
- Adds comprehensive regression test to verify PATH ordering behavior
Reviewed Changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/toolset/mod.rs | Adds list_final_paths_split() method to separate user-configured paths from tool paths |
| src/cli/hook_env.rs | Updates path operations to handle user and tool paths separately, only filtering tool paths |
| e2e/config/test_env_path_ordering | Adds regression test verifying user-configured PATH ordering takes precedence |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Filter out tool paths that are already in the original PATH (post) or | ||
| // in the pre paths (user additions). This prevents mise from claiming ownership |
There was a problem hiding this comment.
The comment should be updated to reflect that this filtering now only applies to tool paths, not all paths as it previously did.
| // Filter out tool paths that are already in the original PATH (post) or | |
| // in the pre paths (user additions). This prevents mise from claiming ownership | |
| // Filter out tool paths (not all paths) that are already in the original PATH (post) or | |
| // in the pre paths (user additions). This filtering now only applies to tool paths, | |
| // not all paths as it previously did. This prevents mise from claiming ownership |
| eval "$(mise hook-env)" | ||
|
|
||
| echo "DEBUG: Final PATH=$PATH" | ||
| echo "DEBUG: __MISE_ORIG_PATH=${__MISE_ORIG_PATH:-not set}" |
There was a problem hiding this comment.
Debug output statements should be removed from the test file as they add noise to test execution and aren't needed for the test assertion logic.
| echo "DEBUG: __MISE_ORIG_PATH=${__MISE_ORIG_PATH:-not set}" |
|
|
||
| # Verify the PATH order by checking which comes first | ||
| WHICH_OUTPUT=$(which test-tool) | ||
| echo "DEBUG: which test-tool = $WHICH_OUTPUT" |
There was a problem hiding this comment.
Debug output statement should be removed from the test file as it adds noise to test execution and isn't needed for the test assertion logic.
| echo "DEBUG: which test-tool = $WHICH_OUTPUT" |
env_results.env_paths (tool-stage _.path) must come BEFORE config.path_dirs() to maintain the original behavior from list_final_paths() where env_results.env_paths had highest precedence (was prepended at the front). The previous implementation reversed this by appending env_results.env_paths after config.path_dirs(), breaking the expected PATH ordering. Co-Authored-By: Claude <noreply@anthropic.com>
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2025.10.21 x -- echo |
18.5 ± 0.4 | 17.9 | 20.4 | 1.00 |
mise x -- echo |
18.9 ± 2.1 | 18.0 | 61.3 | 1.02 ± 0.11 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2025.10.21 env |
18.0 ± 0.4 | 17.5 | 19.6 | 1.00 |
mise env |
18.2 ± 0.5 | 17.5 | 21.9 | 1.01 ± 0.03 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2025.10.21 hook-env |
18.2 ± 0.5 | 17.6 | 21.4 | 1.00 |
mise hook-env |
18.3 ± 0.4 | 17.6 | 21.4 | 1.00 ± 0.04 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2025.10.21 ls |
15.8 ± 0.4 | 15.1 | 17.2 | 1.00 ± 0.03 |
mise ls |
15.8 ± 0.2 | 15.3 | 17.5 | 1.00 |
xtasks/test/perf
| Command | mise-2025.10.21 | mise | Variance |
|---|---|---|---|
| install (cached) | 105ms | 105ms | +0% |
| ls (cached) | 64ms | 64ms | +0% |
| bin-paths (cached) | 70ms | 70ms | +0% |
| task-ls (cached) | 426ms | -11% |
On reactivation, user additions may be in __MISE_ORIG_PATH (post), so we need to filter user_paths against the full current PATH (pre + post) to avoid duplicates. This is a trade-off: it may filter out some user-configured paths that are in __MISE_ORIG_PATH during initial activation, but it avoids creating duplicate paths on reactivation. Co-Authored-By: Claude <noreply@anthropic.com>
The previous implementation filtered user_paths against the full current PATH (pre + post), which included __MISE_ORIG_PATH. This broke the intended fix where user-configured paths from env._.path should take precedence even if they already exist in the original PATH. The correct behavior is: - Filter user_paths against `pre` (user manual additions after mise activation) to avoid duplicates when users manually modify PATH - Do NOT filter against `post` (__MISE_ORIG_PATH) to preserve user's intended PATH ordering from configuration Also updated cli/test_deactivate to reflect correct behavior: on reactivation, shared_entry should appear 3 times (1 from mise config + 2 from user additions), not 2 as the old buggy implementation enforced. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Fixed 3 misleading comments: 1. Line 82: Order doesn't matter for __MISE_DIFF (only used for set membership) 2. Line 182: user_paths ARE filtered (against pre, not post) 3. Lines 235-237: Clarified that tool_paths are filtered against post, and user_paths are filtered separately against pre 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
### 🐛 Bug Fixes - **(activate)** reset PATH when activate is called multiple times by @jdx in [#6829](#6829) - **(env)** preserve user-configured PATH entries from env._.path by @jdx in [#6835](#6835) - store tool options for all backends in metadata by @roele in [#6807](#6807) ### 📚 Documentation - fix usage spec syntax from 'option' to 'flag' by @jdx in [#6834](#6834) ### 📦️ Dependency Updates - update ghcr.io/jdx/mise:alpine docker digest to 7351bbe by @renovate[bot] in [#6826](#6826) - update ghcr.io/jdx/mise:deb docker digest to 3a847f2 by @renovate[bot] in [#6828](#6828) - update ghcr.io/jdx/mise:copr docker digest to 546dffb by @renovate[bot] in [#6827](#6827) - pin jdx/mise-action action to e3d7b8d by @renovate[bot] in [#6825](#6825)
Summary
Fixes a regression introduced in f4dca1b where user-configured paths from
env._.pathwere being filtered out if they already existed in__MISE_ORIG_PATH. This caused incorrect PATH ordering when users explicitly configured paths to ensure precedence.Problem
When a user configured
env._.pathto prepend a directory that was already in their original PATH (e.g.,/opt/homebrew/bin), the filtering logic would remove it, breaking the user's intended PATH ordering.Example:
/usr/bin:/opt/homebrew/binenv._.path = ["/opt/homebrew/bin"]/opt/homebrew/bincomes first/opt/homebrew/binstays in original position (after/usr/bin)Reproduction:
Solution
Separate path handling into two categories:
env._.pathviaconfig.path_dirs()) - filtered only againstpre(user manual additions after mise activation), never againstpost(__MISE_ORIG_PATH)The key insight: We need to avoid duplicates when users manually add paths to PATH after mise activation, but we should NOT filter against the original PATH before mise activation. This preserves the user's intended ordering from configuration while preventing unbounded PATH growth.
Added
list_final_paths_split()to return paths separately, and updatedbuild_path_operations()to only filter tool paths against the original PATH, while user-configured paths are only filtered against user manual additions.Changes
list_final_paths_split()method to separate user vs tool pathsbuild_path_operations()to accept separate user/tool pathspre(user manual additions), NOT againstpost(__MISE_ORIG_PATH)Test Plan
The tests verify:
env._.path🤖 Generated with Claude Code
Note
Separates user-configured and tool PATH entries to keep env._.path precedence, updates PATH/DIRENV_DIFF logic, and adds a regression test with adjusted deactivate assertions.
Toolset::list_final_paths_split()to return(user_paths, tool_paths).hook_envto use split paths for__MISE_DIFFand PATH construction.build_path_operations(...)to:tool_pathsagainst original PATH and user-addedprepaths.user_pathsonly againstpre(not original PATH) to preserve configured precedence.pre->user_paths->tool_paths->postand updateDIRENV_DIFFaccordingly.e2e/config/test_env_path_orderingto verifyenv._.pathprecedence over existing PATH.e2e/cli/test_deactivateto expectshared_entrycount of 3 after reactivation and clarify behavior comments.Written by Cursor Bugbot for commit 9862ca8. This will update automatically on new commits. Configure here.