Skip to content

fix(env): prevent PATH corruption when paths are interleaved with original PATH#6821

Merged
jdx merged 1 commit intomainfrom
fix-path-regression-6820
Oct 30, 2025
Merged

fix(env): prevent PATH corruption when paths are interleaved with original PATH#6821
jdx merged 1 commit intomainfrom
fix-path-regression-6820

Conversation

@jdx
Copy link
Copy Markdown
Owner

@jdx jdx commented Oct 30, 2025

Problem

Users reported that Homebrew tool paths disappeared from PATH after upgrading from v2025.10.19 to v2025.10.20 (#6820).

The issue manifested when paths from the user's original PATH were interleaved with user-added paths (e.g., Homebrew paths).

Example scenario that triggered the bug:

  • Original PATH (when mise was activated): /usr/local/bin:/usr/bin:/bin
  • Current PATH (after shell config ran): /opt/homebrew/opt/curl/bin:/usr/local/bin:/opt/homebrew/opt/findutils/libexec/gnubin:/usr/bin:/bin

The PATH reconstruction logic would break when it encountered the first path from the original PATH (/usr/local/bin), causing any subsequent non-original paths (/opt/homebrew/opt/findutils/libexec/gnubin) to be lost.

Root Cause

Commit 8855cba (#6800) introduced a PATH reconstruction algorithm in build_path_operations() that collected "pre" paths (user additions) by iterating through current PATH and breaking as soon as it found a path that existed in the original PATH.

This assumed PATH would always look like: [new paths] [original PATH]

However, when paths are interleaved (common when shell configurations add paths at different points during initialization), paths appearing after the first original PATH match would be lost.

Solution

Modified build_path_operations() in src/cli/hook_env.rs:

1. Remove early break

Collect ALL paths that aren't in the original PATH, regardless of their position in the current PATH. This correctly handles interleaved paths:

// OLD (buggy):
for path in &current_paths {
    if !orig_set.contains(path) {
        pre.push(path.clone());
    } else {
        break;  // ❌ Stops too early!
    }
}

// NEW (fixed):
for path in &current_paths {
    if !orig_set.contains(path) {
        pre.push(path.clone());
        // ✅ Continues collecting ALL non-original paths
    }
}

2. Enhanced duplicate filtering

Filter installs against both post (original PATH) AND pre (user additions) to prevent duplicates when mise paths from previous activations exist in current PATH.

3. Preserve original behavior

The fix maintains compatibility with existing PATH reconstruction logic while fixing the interleaving bug.

Testing

Added e2e/env/test_path_interleaved_regression to verify the fix works correctly when paths are interleaved with original PATH entries.

Impact

This fix ensures that:

  • ✅ Homebrew tool paths are preserved across mise activations
  • ✅ User-added paths are correctly maintained regardless of their position relative to original PATH
  • ✅ No duplicate paths are introduced
  • ✅ Original PATH is preserved exactly

Fixes #6820

🤖 Generated with Claude Code


Note

Fixes PATH reconstruction to preserve interleaved user paths and avoid duplicates; adds an e2e regression test.

  • Env PATH handling (src/cli/hook_env.rs):
    • Collects all non-original paths into pre (removes early break), supporting interleaved PATH entries.
    • De-duplicates installs against both post (original PATH) and pre (user additions), including canonical path checks.
    • Rebuilds PATH as pre + installs_filtered + post.
  • Tests:
    • Adds e2e regression test e2e/env/test_path_interleaved_regression to verify Homebrew/system paths are preserved when interleaved.

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

…ginal PATH

## Problem

Users reported that Homebrew tool paths disappeared from PATH after
upgrading from v2025.10.19 to v2025.10.20. The issue manifested when
paths from the user's original PATH were interleaved with user-added
paths (e.g., Homebrew paths).

Example scenario that triggered the bug:
- Original PATH: `/usr/local/bin:/usr/bin:/bin`
- Current PATH: `/opt/homebrew/opt/curl/bin:/usr/local/bin:/opt/homebrew/opt/findutils/libexec/gnubin:/usr/bin:/bin`

The PATH reconstruction logic would break when it encountered the first
path from the original PATH (`/usr/local/bin`), causing any subsequent
non-original paths (`/opt/homebrew/opt/findutils/libexec/gnubin`) to be
lost.

## Root Cause

Commit 8855cba introduced a PATH reconstruction algorithm that collected
"pre" paths (user additions) by iterating through current PATH and breaking
as soon as it found a path that existed in the original PATH. This assumed
PATH would always look like: `[new paths] [original PATH]`

However, if paths were interleaved (common when shell configs add paths at
different points), paths after the first original PATH match would be lost.

## Solution

Modified `build_path_operations()` in `src/cli/hook_env.rs`:

1. **Remove early break**: Collect ALL paths that aren't in the original
   PATH, regardless of their position in the current PATH. This handles
   interleaved paths correctly.

2. **Enhanced duplicate filtering**: Filter `installs` against both `post`
   (original PATH) AND `pre` (user additions) to prevent duplicates when
   mise paths from previous activations exist in current PATH.

3. **Preserve original behavior**: The fix maintains compatibility with
   existing PATH reconstruction logic while fixing the interleaving bug.

## Testing

Added `e2e/env/test_path_interleaved_regression` to verify the fix works
correctly when paths are interleaved with original PATH entries.

Fixes #6820

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

Co-Authored-By: Claude <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings October 30, 2025 17:33
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Fixes a PATH corruption bug introduced in v2025.10.20 where user-added paths (like Homebrew tools) were lost when interleaved with original PATH entries. The issue occurred when the PATH reconstruction algorithm would stop collecting "pre" paths after encountering the first original PATH entry, losing any subsequent user additions.

  • Removed early break condition in PATH reconstruction to collect ALL non-original paths
  • Enhanced duplicate filtering to check against both original PATH and user additions
  • Added comprehensive test case for the interleaved PATH scenario

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/cli/hook_env.rs Fixed PATH reconstruction logic to handle interleaved paths and improved duplicate filtering
e2e/env/test_path_interleaved_regression Added test case verifying fix for interleaved PATH scenarios

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@github-actions
Copy link
Copy Markdown

Hyperfine Performance

mise x -- echo

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2025.10.20 x -- echo 20.1 ± 0.6 18.8 25.2 1.00 ± 0.05
mise x -- echo 20.1 ± 0.8 18.7 25.2 1.00

mise env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2025.10.20 env 19.1 ± 0.6 17.9 23.9 1.00
mise env 19.3 ± 0.7 17.8 21.2 1.01 ± 0.05

mise hook-env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2025.10.20 hook-env 19.4 ± 0.5 17.9 23.8 1.00
mise hook-env 19.8 ± 0.7 18.3 22.0 1.02 ± 0.05

mise ls

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2025.10.20 ls 16.7 ± 0.6 15.4 19.7 1.00
mise ls 17.9 ± 0.6 16.6 20.0 1.07 ± 0.05

xtasks/test/perf

Command mise-2025.10.20 mise Variance
install (cached) 112ms 110ms +1%
ls (cached) 66ms 67ms -1%
bin-paths (cached) 72ms 72ms +0%
task-ls (cached) 497ms 483ms +2%

@jdx jdx merged commit baae88e into main Oct 30, 2025
30 checks passed
@jdx jdx deleted the fix-path-regression-6820 branch October 30, 2025 18:01
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