Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions e2e/core/test_python_venv_with_go_backend_deadlock_slow
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/usr/bin/env bash
# Test for deadlock issue between Python venv creation and Go backend tools
# This reproduces the scenario where go:* tools with dependencies would cause
# a circular dependency during environment resolution while creating Python venv.
# fixes https://github.com/jdx/mise/discussions/7059
set -euo pipefail

cat >.mise.toml <<EOF
[tools]
go = "1.25.4"
python = "3.12.3"
"go:github.com/charmbracelet/gum" = "v0.17.0"

[env]
_.python.venv = {path = "{{env.HOME}}/my_venv", create=true}
EOF

# This should complete without timeout (previously would hang indefinitely)
# The go backend tool resolution should not interfere with Python venv creation
timeout 60 mise install

# Verify Python venv was created
assert "mise x -- python --version" "Python 3.12.3"
assert "mise env -s bash | grep VIRTUAL_ENV" "export VIRTUAL_ENV=$HOME/my_venv"
assert "mise x -- which python" "$HOME/my_venv/bin/python"

# Verify Go backend tool was installed and can run
assert_contains "mise x -- gum --version" "0.17.0"

# Required to properly cleanup as go installs read-only sources
chmod -R +w ~/go
25 changes: 21 additions & 4 deletions src/config/env_directive/venv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ use crate::config::{Config, Settings};
use crate::env_diff::EnvMap;
use crate::file::{display_path, which_non_pristine};
use crate::lock_file::LockFile;
use crate::toolset::ToolsetBuilder;
use crate::toolset::Toolset;
use crate::{backend, plugins};
use indexmap::IndexMap;
use std::collections::HashSet;
use std::{
path::{Path, PathBuf},
sync::Arc,
Expand Down Expand Up @@ -41,7 +42,23 @@ impl EnvResults {
if !venv.exists() && create {
// TODO: the toolset stuff doesn't feel like it's in the right place here
// TODO: in fact this should probably be moved to execute at the same time as src/uv.rs runs in ts.env() instead of config.env()
let ts = Box::pin(ToolsetBuilder::new().build(config)).await?;
// Build a toolset with only Python and UV tools to avoid circular dependency deadlock.
// When all tools are resolved (including go:* tools), those tools may need to access
// the environment via dependency_toolset(), which tries to call config.env() again,
// creating a circular wait since we're already in the middle of resolving the venv
// directive as part of config.env().
// By filtering to only Python/UV BEFORE resolution, we avoid resolving unrelated tools
// that have their own dependencies and environment requirements.
let trs = config.get_tool_request_set().await?;
let mut filter = HashSet::new();
filter.insert("python".to_string());
filter.insert("uv".to_string());
let filtered_trs = trs.filter_by_tool(filter);

// Convert the filtered tool request set to a toolset and resolve only these tools
let mut ts: Toolset = filtered_trs.into();
// Ignore resolution errors for venv creation - if tools aren't available, we'll warn below
let _ = ts.resolve(config).await;
let ba = BackendArg::from("python");
let tv = ts.versions.get(&ba).and_then(|tv| {
// if a python version is specified, check if that version is installed
Expand All @@ -65,7 +82,7 @@ impl EnvResults {
true
};
if !installed {
warn!(
warn_once!(
"no venv found at: {p}\n\n\
mise will automatically create the venv once all requested python versions are installed.\n\
To install the missing python versions and create the venv, please run:\n\
Expand Down Expand Up @@ -137,7 +154,7 @@ impl EnvResults {
);
} else if !create {
// The create "no venv found" warning is handled elsewhere
warn!(
warn_once!(
"no venv found at: {p}
To create a virtualenv manually, run:
python -m venv {p}",
Expand Down
Loading