Skip to content

Fix: mise Not Working — Shell Activation, .tool-versions, Plugin Install, and Python venv

FixDevs · (Updated: )

Part of:  JavaScript & TypeScript Errors

Quick Answer

How to fix mise (formerly rtx) errors — activation hook not running, tool not found after install, .tool-versions vs .mise.toml, Python venv integration, idiomatic env loading, and trust prompts.

The Error

You install mise but node still resolves to the system version:

$ mise install node@20
$ node --version
v18.10.0   # System Node — mise's Node 20 isn't being picked up.

Or mise install succeeds but which can’t find the binary:

$ mise install [email protected]
$ which python
python not found

Or .tool-versions is ignored:

# .tool-versions
node 20.18.0
python 3.12.7
$ cd my-project
$ node --version
v18.10.0   # Should be 20.18.0

Or you get repeated “trust” prompts on every directory change:

mise WARN The config file is not trusted. You can trust it with:
  mise trust /path/to/.mise.toml

Why This Happens

mise is a polyglot version manager that replaces asdf, nvm, pyenv, rbenv, and others. It installs tools into ~/.local/share/mise/ and uses a shim or PATH activation to expose them. Most failures come from:

  • Shell activation isn’t loaded. Without mise activate running in your shell init, PATH doesn’t include mise’s tools. mise install works, but the tool isn’t on your PATH.
  • .tool-versions and .mise.toml are both supported, with .mise.toml taking precedence. Projects with both can get confused — usually the .mise.toml wins silently.
  • Project trust. mise refuses to load config from untrusted directories (a security feature against malicious repos with pre-execute hooks). You must mise trust once per project.
  • Plugin name conflicts. Some tools (python, nodejs) have core plugins built in; others come from asdf compatibility. Mismatches cause “no such plugin” errors.

The second-level cause of most “tool not found” reports is environment scoping. mise’s whole model assumes that every shell that should see your project’s tools has run mise activate (or has the shim directory ahead of system paths). Non-interactive shells (cron jobs, systemd services, CI runners that exec a script without sourcing your profile, GUI launchers that spawn processes from the desktop session) don’t read ~/.bashrc or ~/.zshrc. So a binary that resolves perfectly in your interactive terminal disappears the moment a build agent or editor task tries to call it. The same applies to Makefile recipes started by make from outside an activated shell.

A third class of failure traces back to the rtx → mise rename in August 2023. If you installed early (when the project was still called rtx), you may still have an rtx binary on disk, an ~/.config/rtx/ directory with stale config, and shell init lines that call rtx activate. mise reads its own paths (~/.config/mise/, ~/.local/share/mise/) and ignores the legacy ones, so versions you “set” via rtx commands appear to vanish. The fix is a clean migration: remove rtx, replace the activation line, and re-declare your tools via mise use. Mixed installs where both binaries are on PATH lead to whichever one your shell init activates winning — and that is rarely the one you think.

Fix 1: Activate mise in Your Shell

Add to your shell init:

Bash (~/.bashrc):

eval "$(mise activate bash)"

Zsh (~/.zshrc):

eval "$(mise activate zsh)"

Fish (~/.config/fish/config.fish):

mise activate fish | source

PowerShell ($PROFILE):

mise activate pwsh | Out-String | Invoke-Expression

Open a new terminal (or source ~/.zshrc). Verify:

$ which node
/home/you/.local/share/mise/installs/node/20.18.0/bin/node

which node should point at mise’s install directory, not /usr/bin/node.

Pro Tip: Use the --shims mode if mise activate interferes with your shell setup:

# Add the shim dir to PATH (in your shell init):
export PATH="$HOME/.local/share/mise/shims:$PATH"

Shim mode is slower (each command exec’d through a wrapper) but works in non-interactive shells, scripts, and IDEs that don’t load your shell rc files.

Fix 2: Install Tools

After activation:

mise install node@20         # Install latest 20.x
mise install [email protected]    # Pin to exact version
mise install [email protected]     # Latest 3.12.x
mise install rust@latest     # Latest stable
mise install [email protected]

To install everything declared in the current project:

cd my-project
mise install
# Reads .mise.toml / .tool-versions and installs all listed tools.

To set a tool version for the current directory:

mise use node@20        # Adds to .mise.toml in this directory
mise use --global node@20   # Adds to ~/.config/mise/config.toml (default everywhere)

To list installed:

mise list
# node    20.18.0   ~/.config/mise/config.toml
# python  3.12.7    ~/projects/my-app/.mise.toml

Fix 3: .mise.toml vs .tool-versions

.mise.toml (preferred):

[tools]
node = "20.18.0"
python = "3.12.7"
go = "1.23"
rust = { version = "stable", profile = "minimal" }

[env]
DATABASE_URL = "postgres://localhost/myapp"
NODE_ENV = "development"

[tasks.dev]
run = "npm run dev"

[tasks.test]
run = "npm test"

.tool-versions (asdf-compatible):

node 20.18.0
python 3.12.7
go 1.23

mise reads both, with .mise.toml winning if both exist. Use .mise.toml for new projects — it supports env vars and tasks that .tool-versions doesn’t.

For team consistency, commit both — older devs on asdf see .tool-versions, mise users get the richer .mise.toml. Set them to identical versions to avoid drift.

Common Mistake: Editing .tool-versions and assuming mise picked it up. If a .mise.toml exists with different versions, it wins. Run mise list to see what mise actually resolved.

Fix 4: Trust the Project

The first time you cd into a directory with .mise.toml, mise prompts:

mise WARN The config file is not trusted. You can trust it with:
  mise trust /path/to/.mise.toml

Trust the file:

mise trust

This adds the path to ~/.local/share/mise/trusted-configs/. Now mise loads it without prompting.

For CI environments where you can’t interactively trust:

mise trust --all   # In CI scripts before any mise operation.
# Or:
MISE_TRUSTED_CONFIG_PATHS="/path/to/repo" mise install

Note: Trust is a real security control. If a repo’s .mise.toml has pre_install hooks or [env] blocks that execute shell, you don’t want them running automatically on clone. The prompt is one-time per file.

Fix 5: Python venv Integration

mise can auto-create and activate a venv per project:

# .mise.toml
[tools]
python = "3.12.7"

[env]
_.python.venv = { path = ".venv", create = true }

Now cd into the project and mise creates .venv automatically. Any python or pip you run uses that venv.

For uv:

[tools]
python = "3.12.7"
uv = "latest"

[env]
_.python.venv = { path = ".venv", create = true, uv_create_args = ["--seed"] }

For poetry, the venv is managed by poetry — don’t use mise’s venv feature. Just install python via mise:

[tools]
python = "3.12.7"
poetry = "latest"

Pro Tip: Pin both Python and the package manager (uv/poetry) in .mise.toml. Avoids “works on my machine” issues when a teammate has a different poetry version.

Fix 6: Plugin Conflicts and Aliases

Some tools have built-in core plugins (node, python, go, rust). Others come from asdf:

mise plugins ls       # Show installed plugins
mise plugins ls --core   # Show built-in

To install an asdf-compatible plugin:

mise plugins install awscli https://github.com/MetricMike/asdf-awscli.git
mise install [email protected]

For tool aliases (using a different name):

[tools]
nodejs = "20"   # mise treats "nodejs" as alias for "node"

Common Mistake: Installing both python (core) and python (asdf plugin). Pick one. Remove the asdf plugin: mise plugins uninstall python and let the core plugin handle it.

Fix 7: Environment Variables

.mise.toml’s [env] block sets env vars per project:

[env]
DATABASE_URL = "postgres://localhost/dev"
NODE_OPTIONS = "--enable-source-maps"
PATH = "./node_modules/.bin:$PATH"   # Note: $PATH refers to env var

Strings starting with $ reference other env vars. For literal $, escape: \$.

For sensitive values, load from a file:

[env]
_.file = ".env"

This reads .env (gitignored) and exposes its values. mise enforces “trusted file” rules — the .env file’s path must be under a trusted config root.

For derived env from tools:

[env]
_.python.venv = { path = ".venv" }   # Sets VIRTUAL_ENV, prepends PATH

Use mise env to see what mise would inject:

mise env
# export DATABASE_URL=postgres://...
# export VIRTUAL_ENV=/path/to/.venv
# ...

Fix 8: Tasks (Built-in Task Runner)

.mise.toml can define tasks (like Makefile + npm scripts):

[tasks.dev]
description = "Run dev server"
run = "npm run dev"

[tasks.test]
description = "Run tests"
run = "npm test"
depends = ["build"]

[tasks.build]
description = "Build the project"
run = "tsc -p ."

[tasks.deploy]
description = "Deploy to prod"
run = """
npm run build
npm run test
fly deploy
"""

Run with:

mise run dev
mise run test     # Runs build first due to depends
mise tasks ls     # List all tasks

The depends field gives you Make-like dependency chains across tools without a separate Makefile.

Pro Tip: Standardize on mise run <task> across your team. New contributors don’t need to learn each project’s scripts — mise tasks ls is self-documenting.

Version History: rtx, mise, and the Polyglot Race

Knowing where mise came from explains a surprising number of present-day problems.

Pre-2023 — the asdf era. asdf was the de facto polyglot version manager: a Bash-based shim layer that installed plugins per language and read .tool-versions. It worked, but every shell command went through a Bash wrapper, which made python, node, and ruby measurably slow to start. Tab completion lagged, prompts stalled, and pre-commit hooks took a long time to spin up because each hook re-invoked the shim chain.

Early 2023 — rtx 1.x. rtx was launched as a Rust rewrite of asdf with the same .tool-versions format and asdf plugin compatibility. The big win was speed: native PATH-mode activation skipped the shim wrapper entirely, so node resolved directly to the installed binary. It also added .rtx.toml (a richer config than .tool-versions) and started bundling core plugins for popular languages so most users didn’t need to install any plugin at all.

August 2023 — the rename to mise. The project was renamed because “rtx” conflicted with NVIDIA RTX branding and was hard to discover. The binary, config directory, and environment variables all changed (rtxmise, .rtx.toml.mise.toml, RTX_*MISE_*). For a few releases there were compatibility shims that read both names; those were removed in 2024 releases. If your old machine still has ~/.config/rtx/ or shell init lines like eval "$(rtx activate zsh)", you have a half-migrated install.

2024.x series — tasks and env improvements. Tasks (the built-in runner shown in Fix 8) and the [env] block with file-loaded env (_.file = ".env") became the headline features that distinguish mise from asdf. The trust system (Fix 4) was tightened in this period because the [env] block can execute shell.

2025+ — convergence with proto and vfox. Two other tools showed up in the same space: proto (from the moon monorepo team, written in Rust, TOML-based) and vfox (cross-platform plugin-based, Go-based). Practical differences for picking one:

  • mise vs asdf: mise is faster, supports .tool-versions natively, ships core plugins, and adds tasks + env. asdf still wins if you depend on niche community plugins not yet ported.
  • mise vs proto: proto integrates tightly with moon for monorepos; mise is broader (env, tasks, polyglot) but has no opinion about your repo layout.
  • mise vs vfox: vfox emphasizes Windows-native support without WSL. mise’s Windows story improved during 2024 but still leans on shims more heavily.

What this means for debugging. Most “mise not picking up my version” issues on long-lived dev machines trace to either (a) a leftover asdf install (~/.asdf/ plus asdf.sh in .zshrc) competing for PATH, (b) a leftover rtx install from before the rename, or (c) homebrew installing mise while your shell init still calls rtx activate. Run which -a node and echo $PATH first — the first entry on PATH wins, and you can usually see the conflict immediately.

Still Not Working?

A few less-obvious failures:

  • mise: command not found. Install didn’t add mise to PATH. Re-run the installer or add ~/.local/bin (mise’s default install location) to PATH.
  • mise activate triggers errors in non-interactive shells. Use eval "$(mise activate bash --shims)" or set MISE_SHIMS_DIR to a known path.
  • VS Code terminal doesn’t see mise tools. Two causes: (1) VS Code doesn’t load your .zshrc. Set "terminal.integrated.profiles.osx" / "linux" to bash --login or similar. (2) Use shim mode (PATH-based) which works regardless of shell init.
  • Pre-commit hooks run system Node instead of mise Node. Hooks run in a minimal shell. Either configure the hook to source mise activation, or use mise’s shim mode globally.
  • mise install hangs on a tool. Some plugins download from slow upstreams (Python downloads from python.org; Ruby builds from source). Use MISE_INSTALL_LOG_LEVEL=debug to see what’s happening.
  • CI cache misses every run. Cache ~/.local/share/mise between CI runs to avoid re-installing. GitHub Actions: actions/cache@v4 with ~/.local/share/mise as the path.
  • mise outdated doesn’t catch security updates. It compares against the latest version available. For CVE tracking, use a separate tool like npm audit, cargo audit, etc.
  • Conflicts with asdf. If you migrated from asdf, remove ~/.asdf and any asdf lines from your shell rc. mise reads ~/.tool-versions natively.
  • Leftover rtx config silently overrides mise. If ~/.config/rtx/ still exists from a pre-2023 install, some operations may still read it on older mise versions. Remove the directory after confirming the versions are mirrored in ~/.config/mise/.
  • Direnv conflicts with mise’s env loading. If your project has both a .envrc and a [env] block in .mise.toml, the order they evaluate depends on which activated first. Pick one — running both leads to surprising precedence depending on the shell.
  • Homebrew updates mise but not the activation line. After brew upgrade mise, the binary moves but your eval "$(mise activate zsh)" keeps working. If you see “deprecated flag” warnings, the message tells you the new flag — update the activation line, don’t pin an old mise version.

For related toolchain and version-manager issues, see Python virtualenv wrong python, pip externally-managed-environment, uv not working, and Node cannot find module.

F

FixDevs

Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.

Was this article helpful?

Related Articles