Skip to content

fix(upgrade): respect use_locked_version when checking tracked configs#7997

Merged
jdx merged 1 commit intomainfrom
fix/upgrade-prune-lockfile
Feb 4, 2026
Merged

fix(upgrade): respect use_locked_version when checking tracked configs#7997
jdx merged 1 commit intomainfrom
fix/upgrade-prune-lockfile

Conversation

@jdx
Copy link
Owner

@jdx jdx commented Feb 4, 2026

Summary

Fixes mise upgrade incorrectly keeping old versions when lockfile is enabled.

  • When checking which versions are needed by tracked configs during upgrade, the code was always using the lockfile to resolve versions even when use_locked_version was explicitly set to false
  • This caused old versions to be incorrectly kept after upgrade because the lockfile hadn't been updated yet
  • The debug message "Keeping X because it's still needed by a tracked config" would appear even when no tracked config actually needed the old version

Root Cause

In tool_version_list.rs, when resolving versions that aren't "latest", the code was overriding use_locked_version to true regardless of what the caller passed in:

// Before:
ResolveOptions {
    latest_versions: false,
    use_locked_version: true,  // Always true, ignoring caller's setting
    ..opts.clone()
}

Fix

  1. get_versions_needed_by_tracked_configs now explicitly requests use_locked_version: false
  2. ToolVersionList::resolve now respects the caller's use_locked_version setting

Fixes #7991

Test plan

  • Added e2e test test_lockfile_upgrade_prune that verifies old versions are removed after upgrade with lockfile enabled
  • Existing upgrade tests pass
  • Existing prune tests pass
  • Existing lockfile tests pass
  • Unit tests pass

🤖 Generated with Claude Code


Note

Medium Risk
Touches version resolution used by both mise upgrade and mise prune, which can change which tool versions are considered “needed” and therefore uninstalled. Scope is small and covered by a new e2e regression test, but mistakes could lead to unexpected installs/removals when lockfiles are enabled.

Overview
Fixes a lockfile-enabled upgrade regression where mise upgrade could incorrectly keep old tool versions by resolving tracked config requirements from the previously locked version.

get_versions_needed_by_tracked_configs now resolves tracked configs with use_locked_version: false, and ToolVersionList::resolve no longer forces use_locked_version=true for non-latest requests (it inherits the caller’s setting).

Adds an e2e regression test (e2e/lockfile/test_lockfile_upgrade_prune) asserting that upgrading a prefix version updates the lockfile and prunes the old installed version.

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

When checking which versions are needed by tracked configs during
upgrade, the code was always using the lockfile to resolve versions
even when use_locked_version was explicitly set to false. This caused
old versions to be incorrectly kept after upgrade because the lockfile
hadn't been updated yet.

The root cause was in ToolVersionList::resolve which overrode
use_locked_version to true for non-"latest" versions, ignoring the
caller's setting.

Fixes #7991

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings February 4, 2026 13:58
Copy link
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

This PR fixes a bug where mise upgrade incorrectly kept old versions when lockfile was enabled, even when those versions were no longer needed by tracked configs.

Changes:

  • Modified version resolution logic to respect the caller's use_locked_version setting instead of always forcing it to true
  • Updated get_versions_needed_by_tracked_configs to explicitly use use_locked_version: false when checking what versions are needed
  • Added e2e test to verify old versions are correctly pruned after upgrade with lockfile enabled

Reviewed changes

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

File Description
src/toolset/tool_version_list.rs Updated version resolution to respect caller's use_locked_version setting instead of overriding it
src/toolset/mod.rs Modified tracked config version checking to explicitly disable lockfile usage during upgrade
e2e/lockfile/test_lockfile_upgrade_prune Added regression test verifying old versions are removed after upgrade with lockfile enabled

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

@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 critical bug in mise upgrade where the tool would fail to prune old software versions when a lockfile was present. The core issue stemmed from an incorrect handling of version resolution for tracked configurations, where the system would always defer to the lockfile's version, even when it should have been evaluating the latest available versions. The fix ensures that mise now correctly identifies and uninstalls obsolete versions during upgrades, improving version management accuracy and system cleanliness.

Highlights

  • Bug Fix: Addresses an issue where mise upgrade would incorrectly retain old versions when lockfiles were enabled, due to use_locked_version being overridden during tracked config resolution.
  • Tracked Config Resolution Logic: The logic for determining versions needed by tracked configurations now explicitly uses use_locked_version: false during upgrades. This ensures that version resolution is based on actual config requests rather than potentially outdated lockfile entries, which is crucial before the lockfile itself is updated.
  • ToolVersionList::resolve Behavior: The resolve method in ToolVersionList has been updated to respect the use_locked_version setting provided by the caller. Previously, it would inadvertently force use_locked_version to true for non-'latest' version requests, leading to the bug.
  • New E2E Test: A new end-to-end test (test_lockfile_upgrade_prune) has been added to specifically verify that mise upgrade correctly prunes old versions when lockfiles are active, ensuring the bug does not regress.
Changelog
  • e2e/lockfile/test_lockfile_upgrade_prune
    • Added a new end-to-end test case to validate the correct pruning of old versions by mise upgrade when lockfiles are enabled.
  • src/toolset/mod.rs
    • Modified get_versions_needed_by_tracked_configs to explicitly pass use_locked_version: false to the resolve_with_opts method when resolving versions for tracked configurations.
    • Introduced a ResolveOptions struct to control version resolution behavior for tracked configurations.
  • src/toolset/tool_version_list.rs
    • Updated the ToolVersionList::resolve method to honor the use_locked_version setting from the ResolveOptions passed by the caller, instead of hardcoding it to true for non-'latest' requests.
Activity
  • The author identified a bug where mise upgrade was not correctly pruning old versions when lockfiles were enabled, leading to old versions being incorrectly kept.
  • A detailed root cause analysis was provided, pinpointing an override of use_locked_version in ToolVersionList::resolve.
  • A fix was implemented by adjusting get_versions_needed_by_tracked_configs to explicitly request use_locked_version: false and modifying ToolVersionList::resolve to respect this setting.
  • Comprehensive testing was performed, including a new e2e test (test_lockfile_upgrade_prune) and verification of existing upgrade, prune, and lockfile tests, as well as unit tests.
  • The PR description includes a link to the related discussion on GitHub (`mise upgrade` doesn't uninstall unused old versions #7991).
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.

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 correctly addresses a bug in mise upgrade where old tool versions were not being uninstalled when a lockfile was in use. The changes are logical and well-implemented: get_versions_needed_by_tracked_configs now correctly ignores the lockfile, and ToolVersionList::resolve is updated to respect the caller's preference for using the lockfile. The addition of a targeted e2e test is excellent for preventing future regressions. I have one minor suggestion to improve a comment in the new test file for clarity.

Comment on lines +22 to +23
# Create a lockfile with the old version locked
touch mise.lock
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The comment on line 22 is slightly misleading. touch mise.lock creates an empty file to enable lockfile functionality, but it doesn't lock a version itself. The version gets locked by the subsequent mise install command. Consider clarifying the comment to reflect this for future readers.

# Enable lockfile functionality by creating an empty lock file
touch mise.lock

@github-actions
Copy link

github-actions bot commented Feb 4, 2026

Hyperfine Performance

mise x -- echo

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.3 x -- echo 15.8 ± 0.4 14.8 18.0 1.00
mise x -- echo 16.0 ± 0.4 15.0 17.4 1.01 ± 0.04

mise env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.3 env 15.8 ± 0.7 14.4 25.9 1.00
mise env 16.6 ± 0.6 14.9 20.4 1.05 ± 0.06

mise hook-env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.3 hook-env 16.3 ± 0.4 15.1 17.4 1.00
mise hook-env 16.6 ± 0.6 15.2 22.6 1.02 ± 0.04

mise ls

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.3 ls 14.7 ± 0.4 13.6 16.0 1.00
mise ls 15.0 ± 0.4 13.9 16.4 1.02 ± 0.04

xtasks/test/perf

Command mise-2026.2.3 mise Variance
install (cached) 84ms 83ms +1%
ls (cached) 55ms 56ms -1%
bin-paths (cached) 60ms 58ms +3%
task-ls (cached) 455ms 457ms +0%

@jdx jdx merged commit 5c11b37 into main Feb 4, 2026
37 checks passed
@jdx jdx deleted the fix/upgrade-prune-lockfile branch February 4, 2026 17:24
mise-en-dev added a commit that referenced this pull request Feb 5, 2026
### 🐛 Bug Fixes

- **(env)** resolve sourced env for tool templates by @corymhall in
[#7895](#7895)
- **(npm)** only declare the configured package manager as a dependency
by @jdx in [#7995](#7995)
- **(upgrade)** respect use_locked_version when checking tracked configs
by @jdx in [#7997](#7997)
- ignore MISE_TOOL_VERSION in env var parsing by @jdx in
[#8004](#8004)

### New Contributors

- @corymhall made their first contribution in
[#7895](#7895)
lucasew pushed a commit to lucasew/CONTRIB-mise that referenced this pull request Feb 18, 2026
jdx#7997)

## Summary

Fixes `mise upgrade` incorrectly keeping old versions when lockfile is
enabled.

- When checking which versions are needed by tracked configs during
upgrade, the code was always using the lockfile to resolve versions even
when `use_locked_version` was explicitly set to `false`
- This caused old versions to be incorrectly kept after upgrade because
the lockfile hadn't been updated yet
- The debug message "Keeping X because it's still needed by a tracked
config" would appear even when no tracked config actually needed the old
version

## Root Cause

In `tool_version_list.rs`, when resolving versions that aren't "latest",
the code was overriding `use_locked_version` to `true` regardless of
what the caller passed in:

```rust
// Before:
ResolveOptions {
    latest_versions: false,
    use_locked_version: true,  // Always true, ignoring caller's setting
    ..opts.clone()
}
```

## Fix

1. `get_versions_needed_by_tracked_configs` now explicitly requests
`use_locked_version: false`
2. `ToolVersionList::resolve` now respects the caller's
`use_locked_version` setting

Fixes jdx#7991

## Test plan

- [x] Added e2e test `test_lockfile_upgrade_prune` that verifies old
versions are removed after upgrade with lockfile enabled
- [x] Existing upgrade tests pass
- [x] Existing prune tests pass
- [x] Existing lockfile tests pass
- [x] Unit tests pass

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches version resolution used by both `mise upgrade` and `mise
prune`, which can change which tool versions are considered “needed” and
therefore uninstalled. Scope is small and covered by a new e2e
regression test, but mistakes could lead to unexpected installs/removals
when lockfiles are enabled.
> 
> **Overview**
> Fixes a lockfile-enabled upgrade regression where `mise upgrade` could
incorrectly keep old tool versions by resolving tracked config
requirements from the *previously locked* version.
> 
> `get_versions_needed_by_tracked_configs` now resolves tracked configs
with `use_locked_version: false`, and `ToolVersionList::resolve` no
longer forces `use_locked_version=true` for non-`latest` requests (it
inherits the caller’s setting).
> 
> Adds an e2e regression test
(`e2e/lockfile/test_lockfile_upgrade_prune`) asserting that upgrading a
prefix version updates the lockfile and prunes the old installed
version.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
8c068fe. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

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

- **(env)** resolve sourced env for tool templates by @corymhall in
[jdx#7895](jdx#7895)
- **(npm)** only declare the configured package manager as a dependency
by @jdx in [jdx#7995](jdx#7995)
- **(upgrade)** respect use_locked_version when checking tracked configs
by @jdx in [jdx#7997](jdx#7997)
- ignore MISE_TOOL_VERSION in env var parsing by @jdx in
[jdx#8004](jdx#8004)

### New Contributors

- @corymhall made their first contribution in
[jdx#7895](jdx#7895)
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