Skip to content

fix(install): skip tools=true env directives during backend installation#8356

Merged
jdx merged 3 commits intomainfrom
fix/install-env-tools-resolution
Feb 26, 2026
Merged

fix(install): skip tools=true env directives during backend installation#8356
jdx merged 3 commits intomainfrom
fix/install-env-tools-resolution

Conversation

@jdx
Copy link
Owner

@jdx jdx commented Feb 26, 2026

Summary

  • Fix crash when installing cargo/npm/pipx tools alongside tools = true env directives that reference other tools (e.g., {{ tools.node.version }})
  • During installation, referenced tools may not be installed yet, causing template rendering to fail with "Variable not found in context"
  • Add env_with_path_without_tools() that includes tool paths in PATH but skips tools = true env directive resolution, mirroring the approach already used for preinstall hooks
  • Update cargo, npm, and pipx backends to use this method during installation

Fixes #8346

Test plan

  • New e2e test test_install_with_tools_env verifies mise install succeeds with tools = true env vars alongside npm tools
  • Unit tests pass (491/491)
  • Lint passes

🤖 Generated with Claude Code


Note

Medium Risk
Changes tool-install-time environment construction for cargo/npm/pipx, which could affect installs that relied on tools=true env evaluation during install. Scope is limited and covered by a new regression e2e test.

Overview
Fixes a crash during mise install when [env] contains tools = true directives that reference other tools not yet installed.

Adds Toolset::env_with_path_without_tools() (and wires full_env_without_tools() through it) to build an install-time env that still sets up PATH but skips resolving tools=true env entries, then updates the cargo, npm (including bun/pnpm paths), and pipx backends to use it during installation.

Adds an e2e regression test (e2e/backend/test_install_with_tools_env) that installs an npm tool alongside a tools=true env template and asserts mise install succeeds.

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

During tool installation, backends (cargo, npm, pipx) called
env_with_path() which resolves `tools = true` env directives. These
directives may reference tools via templates like
`{{ tools.node.version }}`, but the referenced tools might not be
installed yet, causing template rendering errors.

Add env_with_path_without_tools() that includes tool paths in PATH but
skips `tools = true` env directive resolution, mirroring the approach
already used for preinstall hooks (full_env_without_tools). Update all
backend install callsites to use this method.

Fixes #8346

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 addresses a critical bug preventing successful installation of certain tools when environment variables with tools = true directives were configured to reference other tools not yet present. By introducing a specialized environment resolution method that bypasses these directives during installation, the change ensures a more robust and reliable tool installation experience, preventing crashes and improving overall system stability.

Highlights

  • Fixes Installation Crashes: Resolved an issue where installing cargo, npm, or pipx tools would crash if tools = true environment directives referenced other tools that were not yet installed.
  • Introduced env_with_path_without_tools(): Added a new utility function that provides environment variables with tool paths but specifically skips the resolution of tools = true directives.
  • Backend Integration: Updated the cargo, npm, and pipx backends to utilize the new env_with_path_without_tools() function during their installation processes.
  • New E2E Test: Included a new end-to-end test to verify that mise install now successfully handles tools = true env vars alongside npm tools without errors.
Changelog
  • e2e/backend/test_install_with_tools_env
    • Added a new end-to-end test to verify correct installation behavior with tools = true env vars.
  • src/backend/cargo.rs
    • Updated the cargo backend to use env_with_path_without_tools during installation.
  • src/backend/npm.rs
    • Modified the npm backend to use env_with_path_without_tools for bun and npm installations.
  • src/backend/pipx.rs
    • Changed the pipx backend to use env_with_path_without_tools for both uv and pipx installations.
  • src/toolset/toolset_env.rs
    • Implemented env_with_path_without_tools to provide environment variables without resolving tools = true directives.
Activity
  • A new e2e test test_install_with_tools_env was added to verify the fix.
  • All unit tests passed (491/491).
  • Linting checks passed.
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 crash that occurs during tool installation when tools = true environment directives are present. The approach of introducing env_with_path_without_tools to defer the resolution of these directives is sound, and the updates to the cargo, npm, and pipx backends are appropriate. The addition of an end-to-end test is also a great way to ensure this issue doesn't regress. I have one suggestion to reduce code duplication.

Comment on lines +49 to +63
let (tool_env, add_paths) = self.env(config).await?;
let mut env: EnvMap = env::PRISTINE_ENV.clone().into_iter().collect();
env.extend(tool_env);
let mut path_env = PathEnv::from_iter(env::PATH.clone());
for p in config.path_dirs().await?.clone() {
path_env.add(p);
}
for p in &add_paths {
path_env.add(p.clone());
}
for p in self.list_paths(config).await {
path_env.add(p);
}
env.insert(PATH_KEY.to_string(), path_env.to_string());
Ok(env)
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This function's implementation is identical to full_env_without_tools. To avoid code duplication, you can refactor this to call full_env_without_tools directly.

Suggested change
let (tool_env, add_paths) = self.env(config).await?;
let mut env: EnvMap = env::PRISTINE_ENV.clone().into_iter().collect();
env.extend(tool_env);
let mut path_env = PathEnv::from_iter(env::PATH.clone());
for p in config.path_dirs().await?.clone() {
path_env.add(p);
}
for p in &add_paths {
path_env.add(p.clone());
}
for p in self.list_paths(config).await {
path_env.add(p);
}
env.insert(PATH_KEY.to_string(), path_env.to_string());
Ok(env)
self.full_env_without_tools(config).await

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.

@greptile-apps
Copy link

greptile-apps bot commented Feb 26, 2026

Greptile Summary

Fixed crash during tool installation when config contains tools = true env directives that reference other tools. During installation, referenced tools may not be installed yet, causing template rendering to fail with "Variable not found in context" errors.

The solution adds env_with_path_without_tools() method that skips resolving tools = true env directives while still including tool paths in PATH. This mirrors the existing approach used for preinstall hooks (full_env_without_tools()). Updated cargo, npm (bun/pnpm/npm), and pipx (uv/pipx) backends to use this method during installation.

Key changes:

  • New env_with_path_without_tools() method in toolset_env.rs that includes tool paths but skips tools = true env directive resolution
  • Updated 3 backend installation processes to use the new method
  • Added e2e regression test verifying install succeeds with tools = true env vars

Note: Minor code duplication exists between env_with_path_without_tools() and full_env_without_tools() that could be refactored.

Confidence Score: 4/5

  • This PR is safe to merge with minimal risk - it fixes a real crash with a well-tested solution
  • The fix follows an established pattern already used for preinstall hooks, has good test coverage with a new e2e test, and is limited in scope to only the installation process. Minor code duplication exists but doesn't affect correctness.
  • No files require special attention - all changes follow the same safe pattern

Important Files Changed

Filename Overview
e2e/backend/test_install_with_tools_env New test verifies install succeeds with tools = true env vars
src/toolset/toolset_env.rs Added env_with_path_without_tools() method that duplicates existing full_env_without_tools() logic
src/backend/cargo.rs Updated to use env_with_path_without_tools() during installation
src/backend/npm.rs Updated bun, pnpm, and npm package managers to use env_with_path_without_tools()
src/backend/pipx.rs Updated uv and pipx commands to use env_with_path_without_tools()

Fix All in Claude Code

Last reviewed commit: 866ac31

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

5 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines +48 to +63
pub async fn env_with_path_without_tools(&self, config: &Arc<Config>) -> Result<EnvMap> {
let (tool_env, add_paths) = self.env(config).await?;
let mut env: EnvMap = env::PRISTINE_ENV.clone().into_iter().collect();
env.extend(tool_env);
let mut path_env = PathEnv::from_iter(env::PATH.clone());
for p in config.path_dirs().await?.clone() {
path_env.add(p);
}
for p in &add_paths {
path_env.add(p.clone());
}
for p in self.list_paths(config).await {
path_env.add(p);
}
env.insert(PATH_KEY.to_string(), path_env.to_string());
Ok(env)
Copy link

Choose a reason for hiding this comment

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

This method duplicates the logic of full_env_without_tools() (lines 27-42). Consider refactoring to avoid duplication by having one call the other, or extracting the shared logic into a private helper method.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Claude Code

@github-actions
Copy link

github-actions bot commented Feb 26, 2026

Hyperfine Performance

mise x -- echo

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.21 x -- echo 27.1 ± 0.5 25.9 31.3 1.00
mise x -- echo 27.1 ± 3.7 25.4 96.7 1.00 ± 0.14

mise env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.21 env 26.5 ± 0.7 25.1 34.6 1.00
mise env 26.7 ± 0.7 25.2 35.8 1.01 ± 0.04

mise hook-env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.21 hook-env 27.0 ± 0.6 25.4 31.2 1.00
mise hook-env 27.4 ± 0.6 25.9 31.8 1.01 ± 0.03

mise ls

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.2.21 ls 25.5 ± 0.5 24.0 26.7 1.00
mise ls 25.7 ± 0.7 24.4 34.8 1.01 ± 0.03

xtasks/test/perf

Command mise-2026.2.21 mise Variance
install (cached) 163ms 162ms +0%
ls (cached) 93ms 92ms +1%
bin-paths (cached) 98ms 96ms +2%
task-ls (cached) 867ms 858ms +1%

jdx and others added 2 commits February 26, 2026 11:34
The previous implementation incorrectly started from PRISTINE_ENV (the
full process environment), but env_with_path does not include it. This
caused the full process environment to be passed to backends, overriding
explicitly-set env vars like GITHUB_TOKEN during cargo-binstall.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…th_without_tools

Have full_env_without_tools delegate to env_with_path_without_tools
instead of duplicating the path-building logic.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@jdx jdx merged commit 0805746 into main Feb 26, 2026
35 checks passed
@jdx jdx deleted the fix/install-env-tools-resolution branch February 26, 2026 13:01
mise-en-dev added a commit that referenced this pull request Feb 27, 2026
### 🚀 Features

- add `--outdated` flag to `mise plugins ls` by @jdx in
[#8360](#8360)

### 🐛 Bug Fixes

- **(github)** resolve rename_exe search dir for archives with bin/
subdirectory by @jdx in [#8358](#8358)
- **(install)** skip tools=true env directives during backend
installation by @jdx in [#8356](#8356)
- **(ruby)** resolve correct Windows checksums in lockfile by @jdx in
[#8357](#8357)

### 📦 Registry

- switch terradozer backend to github fork by @chenrui333 in
[#8365](#8365)

### Chore

- **(release)** fix duplicated version prefix in release title by @jdx
in [#8359](#8359)

### New Contributors

- @chenrui333 made their first contribution in
[#8365](#8365)

## 📦 Aqua Registry Updates

#### New Packages (1)

- [`huseyinbabal/taws`](https://github.com/huseyinbabal/taws)

#### Updated Packages (2)

- [`block/goose`](https://github.com/block/goose)
- [`pre-commit/pre-commit`](https://github.com/pre-commit/pre-commit)
risu729 pushed a commit to risu729/mise that referenced this pull request Feb 27, 2026
…ion (jdx#8356)

## Summary

- Fix crash when installing cargo/npm/pipx tools alongside `tools =
true` env directives that reference other tools (e.g., `{{
tools.node.version }}`)
- During installation, referenced tools may not be installed yet,
causing template rendering to fail with "Variable not found in context"
- Add `env_with_path_without_tools()` that includes tool paths in PATH
but skips `tools = true` env directive resolution, mirroring the
approach already used for preinstall hooks
- Update cargo, npm, and pipx backends to use this method during
installation

Fixes jdx#8346

## Test plan

- [ ] New e2e test `test_install_with_tools_env` verifies `mise install`
succeeds with `tools = true` env vars alongside npm tools
- [ ] Unit tests pass (491/491)
- [ ] Lint passes

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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes tool-install-time environment construction for
`cargo`/`npm`/`pipx`, which could affect installs that relied on
`tools=true` env evaluation during install. Scope is limited and covered
by a new regression e2e test.
> 
> **Overview**
> Fixes a crash during `mise install` when `[env]` contains `tools =
true` directives that reference other tools not yet installed.
> 
> Adds `Toolset::env_with_path_without_tools()` (and wires
`full_env_without_tools()` through it) to build an install-time env that
still sets up `PATH` but skips resolving `tools=true` env entries, then
updates the `cargo`, `npm` (including `bun`/`pnpm` paths), and `pipx`
backends to use it during installation.
> 
> Adds an e2e regression test
(`e2e/backend/test_install_with_tools_env`) that installs an npm tool
alongside a `tools=true` env template and asserts `mise install`
succeeds.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
d486725. 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
### 🚀 Features

- add `--outdated` flag to `mise plugins ls` by @jdx in
[jdx#8360](jdx#8360)

### 🐛 Bug Fixes

- **(github)** resolve rename_exe search dir for archives with bin/
subdirectory by @jdx in [jdx#8358](jdx#8358)
- **(install)** skip tools=true env directives during backend
installation by @jdx in [jdx#8356](jdx#8356)
- **(ruby)** resolve correct Windows checksums in lockfile by @jdx in
[jdx#8357](jdx#8357)

### 📦 Registry

- switch terradozer backend to github fork by @chenrui333 in
[jdx#8365](jdx#8365)

### Chore

- **(release)** fix duplicated version prefix in release title by @jdx
in [jdx#8359](jdx#8359)

### New Contributors

- @chenrui333 made their first contribution in
[jdx#8365](jdx#8365)

## 📦 Aqua Registry Updates

#### New Packages (1)

- [`huseyinbabal/taws`](https://github.com/huseyinbabal/taws)

#### Updated Packages (2)

- [`block/goose`](https://github.com/block/goose)
- [`pre-commit/pre-commit`](https://github.com/pre-commit/pre-commit)
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