Recently, we’ve received a few user reports about being unable to select certain Conda environments. Without reliable repro steps, it’s been difficult for us to narrow down the root cause, so I asked Copilot to perform a full audit of all Conda-related code paths to help identify potential issues. I’m planning to go through the findings one by one.
Audit of all conda environment and active environment code paths in vscode-python-environments, motivated by user reports of being unable to select certain conda Python environments as the active interpreter.
Files audited: condaEnvManager.ts, condaUtils.ts, condaSourcingUtils.ts, condaStepBasedFlow.ts, condaPackageManager.ts, envManagers.ts, envCommands.ts, fastPath.ts, pathUtils.ts, deferred.ts
Bug 1 (Critical): set() for global scope does not update in-memory globalEnv
File: src/managers/conda/condaEnvManager.ts, lines 313–314
What happens: When a user selects a conda environment as the global interpreter, set(undefined, environment) persists the selection to disk via setCondaForGlobal(), but never updates this.globalEnv in memory. Subsequent calls to get(undefined) (line 305: return this.globalEnv) return the stale old environment.
Comparison with venvManager.ts (lines 407–414), which correctly does:
const before = this.globalEnv;
this.globalEnv = environment;
await setVenvForGlobal(environment?.environmentPath.fsPath);
Repro steps:
- Open VS Code with no workspace folders (so the scope is global).
- Select a conda environment as the Python interpreter.
- The status bar briefly shows the new environment (from the orchestrator's event), but any subsequent call to
getEnvironment(undefined) — e.g. opening a new terminal, running a script, or the status bar refreshing — returns the old environment.
- The selection appears to revert or flicker back to the previous environment.
Why it's a bug: The orchestrator's getEnvironment() method (in envManagers.ts line 526) calls manager.get(scope), which returns this.globalEnv. Since the in-memory field was never updated, the persisted selection is effectively invisible until VS Code is restarted (when loadEnvMap re-reads from persistent state).
Proposed fix: Update the in-memory state before persisting, matching the venv manager pattern:
if (scope === undefined) {
this.globalEnv = checkedEnv;
await setCondaForGlobal(checkedEnv?.environmentPath?.fsPath);
}
Bug 2 (Critical): set() for global and single-Uri scopes never fires _onDidChangeEnvironment
File: src/managers/conda/condaEnvManager.ts, lines 313–336
What happens: The scope === undefined branch (line 313) and the scope instanceof Uri branch (line 315) persist the selection and update maps, but never fire _onDidChangeEnvironment. Only the Uri[] branch (line 337) fires it.
Comparison with venvManager.ts which fires the event in all three branches (lines 413, 444, 477).
Impact: Any component that directly listens to CondaEnvManager.onDidChangeEnvironment (rather than the orchestrator's higher-level _onDidChangeEnvironmentFiltered) will miss updates. The orchestrator partially masks this by firing its own event, but downstream consumers that rely on the manager-level event — such as terminal activation logic or environment variable injection — may not react to the change.
Repro steps:
- Open a workspace with a single Python project.
- Select a conda environment for that project.
- The selection is persisted and the orchestrator fires its event, but the manager's
onDidChangeEnvironment event never fires.
- Components listening to the manager-level event (not the orchestrator) will not update. This may manifest as stale terminal activation or environment variable state.
Proposed fix: Fire _onDidChangeEnvironment in both branches, tracking the "before" state and comparing with the new state:
if (scope === undefined) {
const before = this.globalEnv;
this.globalEnv = checkedEnv;
await setCondaForGlobal(checkedEnv?.environmentPath?.fsPath);
if (before?.envId.id !== checkedEnv?.envId.id) {
this._onDidChangeEnvironment.fire({ uri: undefined, old: before, new: checkedEnv });
}
} else if (scope instanceof Uri) {
// ... existing map update and persist logic ...
const before = /* capture before the update */;
if (before?.envId.id !== checkedEnv?.envId.id) {
this._onDidChangeEnvironment.fire({ uri: scope, old: before, new: checkedEnv });
}
}
Bug 3 (High): Wrong Python executable path on Linux/macOS after creating conda environments
File: src/managers/conda/condaUtils.ts, lines 1085+1103 (createNamedCondaEnvironment) and lines 1169+1177 (createPrefixCondaEnvironment)
What happens: The code sets:
const bin = os.platform() === 'win32' ? 'python.exe' : 'python';
Then uses path.join(envPath, bin). On Linux/macOS, this produces /path/to/env/python, but conda places the executable at /path/to/env/bin/python.
Comparison with quickCreateConda (line 1225) which correctly does:
os.platform() === 'win32' ? path.join(prefix, 'python.exe') : path.join(prefix, 'bin', 'python')
Repro steps:
- On Linux or macOS, create a conda environment through the VS Code UI (either named or prefix type, using the "Create Environment" command).
- The environment appears in the picker and can be selected.
- However,
execInfo.run.executable points to /path/to/env/python which does not exist.
- Running scripts, getting version info, linting, or any operation that invokes the Python executable will fail silently or with an error.
- The user perceives this as "I selected the environment but it doesn't work."
Why it's a bug: The environment is created successfully by conda, and it appears in the UI as selectable. But the internal executable path is wrong, so the environment is effectively broken after selection. The user sees a valid-looking conda environment they can select, but nothing works after selecting it.
Proposed fix: Change both locations to:
const bin = os.platform() === 'win32' ? 'python.exe' : path.join('bin', 'python');
Bug 4 (Medium): createNamedCondaEnvironment crashes when env not found in known prefixes
File: src/managers/conda/condaUtils.ts, lines 1089–1097
What happens: After conda create --name <name> succeeds, the code searches for the new environment directory in getPrefixes(). If the env is not found in any known prefix directory, envPath stays as the empty string ''. Then getVersion('') tries to read path.join('', 'conda-meta'), which resolves to conda-meta relative to the current working directory. This throws an ENOENT error, and the creation appears to fail even though conda actually created the environment successfully.
Repro steps:
- Configure conda with a custom
envs_dirs in .condarc that differs from the cached prefixes (e.g., add a new directory after the extension already cached the prefix list, or use a non-default conda installation).
- Create a named conda environment through the extension UI.
- Conda creates the environment successfully on disk.
- The extension fails to locate it in the known prefixes,
envPath stays empty.
getVersion('') throws, the progress notification shows "Failed to create conda environment."
- The environment exists on disk but is not registered in the extension.
Why it's a bug: getPrefixes() caches results and may be stale. There is no fallback to re-query conda or to search for the environment by running conda env list.
Proposed fix: After the prefix search loop, check if envPath is empty and either:
- Re-query
conda info --envs --json with cache invalidation, or
- Run
conda env list --json to find the actual path, or
- Throw a descriptive error that guides the user (rather than a cryptic ENOENT).
Bug 5 (Medium): Step-based flow causes double-prompt for environment name
File: src/managers/conda/condaStepBasedFlow.ts line 318, src/managers/conda/condaUtils.ts lines 1052–1058
What happens: The step-based wizard collects the environment name in enterEnvironmentName() (step 3a), storing it in state.envName. Then it calls:
createNamedCondaEnvironment(api, log, manager, state.envName, state.pythonVersion)
But createNamedCondaEnvironment always shows an input box (line 1053) with the name pre-filled, regardless of whether a name was already provided. The user must confirm the name a second time.
Repro steps:
- Run the "Create Environment" command and select Conda.
- Pick "Named" environment type.
- Pick a Python version.
- Enter the name "myenv" and press Enter.
- A second input box appears with "myenv" pre-filled, asking for the name again.
- The user must press Enter again to proceed.
Why it's a bug: The step-based wizard was designed to collect all inputs up front, but the underlying creation function re-prompts. This is confusing UX and may make users think something went wrong.
Proposed fix: Add a parameter to createNamedCondaEnvironment to skip the input box when a name is already provided:
export async function createNamedCondaEnvironment(
api, log, manager, name?, pythonVersion?, skipNamePrompt = false
): Promise<PythonEnvironment | undefined> {
if (!skipNamePrompt || !name) {
name = await showInputBoxWithButtons({ ... });
if (!name) return;
}
// ... rest of creation logic
}
Or refactor so the step flow calls the lower-level creation logic directly, bypassing the UI prompt.
Bug 6 (Medium): Step-based flow discards user-chosen prefix for prefix environments
File: src/managers/conda/condaStepBasedFlow.ts lines 269, 319–321; src/managers/conda/condaUtils.ts lines 1121–1200
What happens: In the step flow, the user chooses a prefix name in enterPrefixName(), which computes:
state.prefix = path.isAbsolute(name) ? name : path.join(state.fsPath, name);
But line 321 passes state.fsPath (the parent directory), not state.prefix:
return await createPrefixCondaEnvironment(api, log, manager, state.fsPath, state.pythonVersion);
The createPrefixCondaEnvironment function then re-derives the prefix name from scratch (defaulting to .conda), and if .conda already exists, prompts the user again for a different name — completely discarding the name they already entered in the wizard.
Repro steps:
- Run "Create Environment" → select Conda → pick "Prefix" → pick Python version.
- Select a workspace folder.
- The default
.conda already exists, so enter a custom name like "myenv".
- The wizard completes, but then another prompt appears asking for a name because
.conda exists.
- The name "myenv" from the wizard step is lost.
Why it's a bug: The step-based flow was introduced to provide a clean wizard experience, but the state collected in earlier steps is not correctly passed through to the creation function.
Proposed fix: Pass state.prefix directly to the creation function and add a parameter to skip the re-prompting logic when a prefix path is already fully resolved:
} else if (state.envType === CondaStrings.condaPrefix && state.prefix) {
return await createPrefixCondaEnvironment(api, log, manager, state.prefix, state.pythonVersion, true);
}
Where true indicates the prefix is already fully resolved and no name prompting is needed.
Bug 7 (Low): getVersion() only finds Python 3.x environments
File: src/managers/conda/condaUtils.ts, line 332
What happens: The version detection looks for files matching file.startsWith('python-3') in the conda-meta directory. This means:
- Python 2.7 conda environments →
python-2.7.18-...json → not matched → throws Error('Python version not found')
- Any future Python 4.x → also not matched
Repro steps:
- Create a conda environment with Python 2.7:
conda create -n py27 python=2.7
- The extension attempts to discover or create an environment item for it.
getVersion() throws because no file starts with python-3.
- The environment creation/resolution fails.
Why it's a bug: While Python 2 is EOL, some organizations still maintain legacy conda environments with Python 2.7. The hardcoded python-3 prefix unnecessarily restricts version detection.
Proposed fix: Change the filter to match any Python version:
if (file.startsWith('python-') && file.endsWith('.json') && /^python-\d/.test(file)) {
Bug 8 (Low): createPrefixCondaEnvironment has weak name-exists validation
File: src/managers/conda/condaUtils.ts, lines 1140–1145
What happens: When .conda already exists and the user is prompted for a new name, the validateInput callback only checks if (value === name) (where name is './.conda'). It does not check whether the proposed new path already exists on disk.
Comparison with the step-based flow's enterPrefixName() (lines 246–252) which correctly calls fse.pathExists(fullPath).
Repro steps:
- A workspace folder has both
.conda/ and .conda2/ directories.
- Create a prefix conda environment via the non-step-based flow.
- Prompted for a new name since
.conda exists → enter .conda2.
- Validation passes (it only checks
value !== './.conda').
conda create --prefix /path/.conda2 fails because the directory already exists.
- User sees "Failed to create conda environment" with no clear reason.
Proposed fix: Replace the string-equality check with an actual filesystem existence check:
validateInput: async (value) => {
if (!value) return l10n.t('Name cannot be empty');
const fullPath = path.isAbsolute(value) ? value : path.join(fsPath, value);
if (await fse.pathExists(fullPath)) {
return CondaStrings.condaExists;
}
return undefined;
},
Bug 9 (Low): Race condition in _runConda — incomplete stderr in error messages
File: src/managers/conda/condaUtils.ts, lines 240–247
What happens: Node.js process events have a defined order: exit can fire before all data events on stdout/stderr are consumed. The close event fires only after all stdio streams are fully drained. In the current code:
exit handler (line 243): If exit code ≠ 0, immediately calls deferred.reject() with the current stderr content.
close handler (line 240): Calls deferred.resolve() — but this is a no-op if the deferred was already rejected.
The problem is that stderr may not be fully populated when exit fires, so error messages can be truncated.
Repro steps:
- Run a conda command that fails with a large stderr output (e.g., a dependency conflict with many package resolution details).
- The error message shown to the user may be missing the end of the output.
- This makes it harder to diagnose why a conda operation failed.
Proposed fix: Store the exit code from the exit event and only resolve/reject in the close handler:
let exitCode: number | null = null;
proc.on('exit', (code) => {
exitCode = code;
});
proc.on('close', () => {
if (exitCode !== null && exitCode !== 0) {
deferred.reject(new Error(`Failed to run "conda ${args.join(' ')}":\n ${stderr}`));
} else {
deferred.resolve(stdout);
}
});
Bug 10 (Critical): Cancelling "Install Python" dialog silently clears the previous environment selection
File: src/managers/conda/condaEnvManager.ts, lines 309–338; src/managers/conda/condaUtils.ts, lines 1467–1494
What happens: When a user selects a conda environment that has no Python installed (version === 'no-python'), checkForNoPythonCondaEnvironment shows a modal dialog asking to install Python. If the user clicks Cancel (or Escape), the function returns undefined. Back in set(), checkedEnv is undefined, so the code proceeds to clear the existing selection:
scope === undefined: setCondaForGlobal(undefined) → clears the global selection
scope instanceof Uri: fsPathToEnv.delete(normalizedFsPath) + setCondaForWorkspace(fsPath, undefined) → clears the workspace selection
scope is array: same deletion for every project
The user's previous, perfectly valid environment selection is silently destroyed. They didn't intend to deselect — they just declined installing Python in a different environment.
Repro steps:
- Have a workspace with a working conda env selected (e.g., "myenv" with Python 3.11).
- In the env picker, select a conda environment that has no Python (shows with a stop icon and "(no-python)" label).
- A modal dialog appears: "Conda environment without Python... Install Python?"
- Click Cancel or press Escape.
- The previous selection ("myenv") is now gone. The workspace falls back to the global default or "base".
- The user has to manually re-select their previous environment.
Why it's a bug: The intent of the modal dialog is to give the user a chance to install Python into the no-python env. Declining should be a no-op — the user is saying "I don't want to switch to this env after all." Instead, the code treats the cancellation as "clear the current selection."
Proposed fix: Early-return from set() when checkForNoPythonCondaEnvironment returns undefined for a no-python environment, preserving the previous selection:
async set(scope: SetEnvironmentScope, environment?: PythonEnvironment | undefined): Promise<void> {
const checkedEnv = environment
? await checkForNoPythonCondaEnvironment(this.nativeFinder, this, environment, this.api, this.log)
: undefined;
// If user cancelled the "install Python" dialog, don't modify existing selection
if (environment && !checkedEnv && environment.version === 'no-python') {
return;
}
// ... rest of method
}
Bug 11 (Medium): loadEnvMap auto-assigns a single local conda env to ALL projects in multi-root workspaces
File: src/managers/conda/condaEnvManager.ts, lines 475–477
What happens: In loadEnvMap(), the code collects pathSorted — conda environments whose environmentPath is inside any project directory. Then for each project without an explicit user selection:
if (pathSorted.length === 1) {
this.fsPathToEnv.set(normalizedPath, pathSorted[0]);
}
When there is exactly one project-local conda env in the entire workspace, it gets auto-assigned to every project that doesn't have an explicit selection — including projects in completely unrelated workspace folders.
Repro steps:
- Open a multi-root workspace with two folders:
/projectA and /projectB.
- Create a conda environment inside
/projectA (e.g., /projectA/.conda).
- Neither project has an explicit conda env selection persisted.
- The extension initializes —
loadEnvMap() finds one local conda env (pathSorted.length === 1).
- Both
/projectA and /projectB get mapped to /projectA/.conda.
- The user sees projectA's conda env as the active environment for projectB, which is incorrect and confusing.
Why it's a bug: The auto-assignment logic does not check whether the single env is actually inside the project being assigned. It blindly assigns to all projects. The pathSorted.length > 1 branch correctly checks project ownership via getPythonProject(e.environmentPath), but the === 1 branch skips this check.
Proposed fix: Only auto-assign when the env is inside the same project:
if (pathSorted.length === 1) {
const envProject = this.api.getPythonProject(pathSorted[0].environmentPath);
if (envProject && normalizePath(envProject.uri.fsPath) === normalizedPath) {
this.fsPathToEnv.set(normalizedPath, pathSorted[0]);
}
}
Bug 12 (Low-Medium): Step-based flow has broken regex for version sorting
File: src/managers/conda/condaStepBasedFlow.ts, line 118
What happens: The parseMajorMinor function uses a double-escaped regex:
const m = v.match(/^(\\d+)(?:\\.(\\d+))?/);
In a JavaScript regex literal, \\d matches a literal backslash followed by the letter d — not a digit. The correct regex (as used in the identical function in condaUtils.ts line 998) is:
const m = v.match(/^(\d+)(?:\.(\d+))?/);
Since the regex never matches version strings like "3.13", parseMajorMinor always returns {major: 0, minor: 0}. The sort() comparator sees all items as equal, so versions appear in arbitrary Set iteration order rather than descending (3.13, 3.12, 3.11, ...).
Repro steps:
- Use "Create Environment" → Conda → select environment type (Named or Prefix).
- The "Select Python version" picker appears.
- Versions are NOT sorted descending — they appear in random/insertion order.
- The recommended version may not be easy to find.
Impact: This doesn't prevent selecting an environment, but it degrades UX and may cause users to pick the wrong version. The fallback list ['3.13', '3.12', '3.11', '3.10', '3.9'] happens to be in correct order, but only triggers when versions.length === 0 (no envs discovered at all).
Proposed fix: Fix the regex to use single backslashes:
const m = v.match(/^(\d+)(?:\.(\d+))?/);
Summary
| # |
Severity |
File |
Bug |
Most likely "can't select" cause? |
| 1 |
Critical |
condaEnvManager.ts |
set() global scope doesn't update globalEnv in memory |
Yes — selection reverts |
| 2 |
Critical |
condaEnvManager.ts |
set() missing change events for global/single-Uri |
Yes — listeners miss updates |
| 3 |
High |
condaUtils.ts |
Wrong Python exe path on Linux/macOS after creation |
Yes — env appears valid but is broken |
| 4 |
Medium |
condaUtils.ts |
Empty envPath crash after named env creation |
Partially — creation fails silently |
| 5 |
Medium |
condaStepBasedFlow.ts + condaUtils.ts |
Double-prompt for name in wizard |
UX confusion |
| 6 |
Medium |
condaStepBasedFlow.ts + condaUtils.ts |
Wizard discards user-chosen prefix |
UX confusion, wrong env created |
| 7 |
Low |
condaUtils.ts |
getVersion() only finds Python 3.x |
Legacy env creation fails |
| 8 |
Low |
condaUtils.ts |
Weak prefix name-exists validation |
Possible creation failure |
| 9 |
Low |
condaUtils.ts |
Race in _runConda stderr |
Truncated error messages |
| 10 |
Critical |
condaEnvManager.ts + condaUtils.ts |
Cancelling "Install Python" dialog clears previous selection |
Yes — previous selection destroyed |
| 11 |
Medium |
condaEnvManager.ts |
Single local env auto-assigned to all projects in multi-root |
Wrong env for unrelated projects |
| 12 |
Low-Medium |
condaStepBasedFlow.ts |
Broken regex in version sorting |
Unsorted version picker |
Bugs 1, 3, and 10 are the most likely root causes of the reported "can't select certain conda environment" issues. Bug 1 causes global selections to silently revert. Bug 3 causes newly created environments on Linux/macOS to have non-functional Python executable paths. Bug 10 causes previous selections to be silently destroyed when users encounter and dismiss no-python environments.
Recently, we’ve received a few user reports about being unable to select certain Conda environments. Without reliable repro steps, it’s been difficult for us to narrow down the root cause, so I asked Copilot to perform a full audit of all Conda-related code paths to help identify potential issues. I’m planning to go through the findings one by one.
Audit of all conda environment and active environment code paths in vscode-python-environments, motivated by user reports of being unable to select certain conda Python environments as the active interpreter.
Files audited:
condaEnvManager.ts,condaUtils.ts,condaSourcingUtils.ts,condaStepBasedFlow.ts,condaPackageManager.ts,envManagers.ts,envCommands.ts,fastPath.ts,pathUtils.ts,deferred.tsBug 1 (Critical):
set()for global scope does not update in-memoryglobalEnvFile:
src/managers/conda/condaEnvManager.ts, lines 313–314What happens: When a user selects a conda environment as the global interpreter,
set(undefined, environment)persists the selection to disk viasetCondaForGlobal(), but never updatesthis.globalEnvin memory. Subsequent calls toget(undefined)(line 305:return this.globalEnv) return the stale old environment.Comparison with venvManager.ts (lines 407–414), which correctly does:
Repro steps:
getEnvironment(undefined)— e.g. opening a new terminal, running a script, or the status bar refreshing — returns the old environment.Why it's a bug: The orchestrator's
getEnvironment()method (inenvManagers.tsline 526) callsmanager.get(scope), which returnsthis.globalEnv. Since the in-memory field was never updated, the persisted selection is effectively invisible until VS Code is restarted (whenloadEnvMapre-reads from persistent state).Proposed fix: Update the in-memory state before persisting, matching the venv manager pattern:
Bug 2 (Critical):
set()for global and single-Uri scopes never fires_onDidChangeEnvironmentFile:
src/managers/conda/condaEnvManager.ts, lines 313–336What happens: The
scope === undefinedbranch (line 313) and thescope instanceof Uribranch (line 315) persist the selection and update maps, but never fire_onDidChangeEnvironment. Only theUri[]branch (line 337) fires it.Comparison with venvManager.ts which fires the event in all three branches (lines 413, 444, 477).
Impact: Any component that directly listens to
CondaEnvManager.onDidChangeEnvironment(rather than the orchestrator's higher-level_onDidChangeEnvironmentFiltered) will miss updates. The orchestrator partially masks this by firing its own event, but downstream consumers that rely on the manager-level event — such as terminal activation logic or environment variable injection — may not react to the change.Repro steps:
onDidChangeEnvironmentevent never fires.Proposed fix: Fire
_onDidChangeEnvironmentin both branches, tracking the "before" state and comparing with the new state:Bug 3 (High): Wrong Python executable path on Linux/macOS after creating conda environments
File:
src/managers/conda/condaUtils.ts, lines 1085+1103 (createNamedCondaEnvironment) and lines 1169+1177 (createPrefixCondaEnvironment)What happens: The code sets:
Then uses
path.join(envPath, bin). On Linux/macOS, this produces/path/to/env/python, but conda places the executable at/path/to/env/bin/python.Comparison with
quickCreateConda(line 1225) which correctly does:Repro steps:
execInfo.run.executablepoints to/path/to/env/pythonwhich does not exist.Why it's a bug: The environment is created successfully by conda, and it appears in the UI as selectable. But the internal executable path is wrong, so the environment is effectively broken after selection. The user sees a valid-looking conda environment they can select, but nothing works after selecting it.
Proposed fix: Change both locations to:
Bug 4 (Medium):
createNamedCondaEnvironmentcrashes when env not found in known prefixesFile:
src/managers/conda/condaUtils.ts, lines 1089–1097What happens: After
conda create --name <name>succeeds, the code searches for the new environment directory ingetPrefixes(). If the env is not found in any known prefix directory,envPathstays as the empty string''. ThengetVersion('')tries to readpath.join('', 'conda-meta'), which resolves toconda-metarelative to the current working directory. This throws an ENOENT error, and the creation appears to fail even though conda actually created the environment successfully.Repro steps:
envs_dirsin.condarcthat differs from the cached prefixes (e.g., add a new directory after the extension already cached the prefix list, or use a non-default conda installation).envPathstays empty.getVersion('')throws, the progress notification shows "Failed to create conda environment."Why it's a bug:
getPrefixes()caches results and may be stale. There is no fallback to re-query conda or to search for the environment by runningconda env list.Proposed fix: After the prefix search loop, check if
envPathis empty and either:conda info --envs --jsonwith cache invalidation, orconda env list --jsonto find the actual path, orBug 5 (Medium): Step-based flow causes double-prompt for environment name
File:
src/managers/conda/condaStepBasedFlow.tsline 318,src/managers/conda/condaUtils.tslines 1052–1058What happens: The step-based wizard collects the environment name in
enterEnvironmentName()(step 3a), storing it instate.envName. Then it calls:But
createNamedCondaEnvironmentalways shows an input box (line 1053) with the name pre-filled, regardless of whether a name was already provided. The user must confirm the name a second time.Repro steps:
Why it's a bug: The step-based wizard was designed to collect all inputs up front, but the underlying creation function re-prompts. This is confusing UX and may make users think something went wrong.
Proposed fix: Add a parameter to
createNamedCondaEnvironmentto skip the input box when a name is already provided:Or refactor so the step flow calls the lower-level creation logic directly, bypassing the UI prompt.
Bug 6 (Medium): Step-based flow discards user-chosen prefix for prefix environments
File:
src/managers/conda/condaStepBasedFlow.tslines 269, 319–321;src/managers/conda/condaUtils.tslines 1121–1200What happens: In the step flow, the user chooses a prefix name in
enterPrefixName(), which computes:But line 321 passes
state.fsPath(the parent directory), notstate.prefix:The
createPrefixCondaEnvironmentfunction then re-derives the prefix name from scratch (defaulting to.conda), and if.condaalready exists, prompts the user again for a different name — completely discarding the name they already entered in the wizard.Repro steps:
.condaalready exists, so enter a custom name like "myenv"..condaexists.Why it's a bug: The step-based flow was introduced to provide a clean wizard experience, but the state collected in earlier steps is not correctly passed through to the creation function.
Proposed fix: Pass
state.prefixdirectly to the creation function and add a parameter to skip the re-prompting logic when a prefix path is already fully resolved:Where
trueindicates the prefix is already fully resolved and no name prompting is needed.Bug 7 (Low):
getVersion()only finds Python 3.x environmentsFile:
src/managers/conda/condaUtils.ts, line 332What happens: The version detection looks for files matching
file.startsWith('python-3')in theconda-metadirectory. This means:python-2.7.18-...json→ not matched → throwsError('Python version not found')Repro steps:
conda create -n py27 python=2.7getVersion()throws because no file starts withpython-3.Why it's a bug: While Python 2 is EOL, some organizations still maintain legacy conda environments with Python 2.7. The hardcoded
python-3prefix unnecessarily restricts version detection.Proposed fix: Change the filter to match any Python version:
Bug 8 (Low):
createPrefixCondaEnvironmenthas weak name-exists validationFile:
src/managers/conda/condaUtils.ts, lines 1140–1145What happens: When
.condaalready exists and the user is prompted for a new name, thevalidateInputcallback only checksif (value === name)(wherenameis'./.conda'). It does not check whether the proposed new path already exists on disk.Comparison with the step-based flow's
enterPrefixName()(lines 246–252) which correctly callsfse.pathExists(fullPath).Repro steps:
.conda/and.conda2/directories..condaexists → enter.conda2.value !== './.conda').conda create --prefix /path/.conda2fails because the directory already exists.Proposed fix: Replace the string-equality check with an actual filesystem existence check:
Bug 9 (Low): Race condition in
_runConda— incomplete stderr in error messagesFile:
src/managers/conda/condaUtils.ts, lines 240–247What happens: Node.js process events have a defined order:
exitcan fire before alldataevents on stdout/stderr are consumed. Thecloseevent fires only after all stdio streams are fully drained. In the current code:exithandler (line 243): If exit code ≠ 0, immediately callsdeferred.reject()with the currentstderrcontent.closehandler (line 240): Callsdeferred.resolve()— but this is a no-op if the deferred was already rejected.The problem is that
stderrmay not be fully populated whenexitfires, so error messages can be truncated.Repro steps:
Proposed fix: Store the exit code from the
exitevent and only resolve/reject in theclosehandler:Bug 10 (Critical): Cancelling "Install Python" dialog silently clears the previous environment selection
File:
src/managers/conda/condaEnvManager.ts, lines 309–338;src/managers/conda/condaUtils.ts, lines 1467–1494What happens: When a user selects a conda environment that has no Python installed (
version === 'no-python'),checkForNoPythonCondaEnvironmentshows a modal dialog asking to install Python. If the user clicks Cancel (or Escape), the function returnsundefined. Back inset(),checkedEnvisundefined, so the code proceeds to clear the existing selection:scope === undefined:setCondaForGlobal(undefined)→ clears the global selectionscope instanceof Uri:fsPathToEnv.delete(normalizedFsPath)+setCondaForWorkspace(fsPath, undefined)→ clears the workspace selectionscopeis array: same deletion for every projectThe user's previous, perfectly valid environment selection is silently destroyed. They didn't intend to deselect — they just declined installing Python in a different environment.
Repro steps:
Why it's a bug: The intent of the modal dialog is to give the user a chance to install Python into the no-python env. Declining should be a no-op — the user is saying "I don't want to switch to this env after all." Instead, the code treats the cancellation as "clear the current selection."
Proposed fix: Early-return from
set()whencheckForNoPythonCondaEnvironmentreturnsundefinedfor a no-python environment, preserving the previous selection:Bug 11 (Medium):
loadEnvMapauto-assigns a single local conda env to ALL projects in multi-root workspacesFile:
src/managers/conda/condaEnvManager.ts, lines 475–477What happens: In
loadEnvMap(), the code collectspathSorted— conda environments whoseenvironmentPathis inside any project directory. Then for each project without an explicit user selection:When there is exactly one project-local conda env in the entire workspace, it gets auto-assigned to every project that doesn't have an explicit selection — including projects in completely unrelated workspace folders.
Repro steps:
/projectAand/projectB./projectA(e.g.,/projectA/.conda).loadEnvMap()finds one local conda env (pathSorted.length === 1)./projectAand/projectBget mapped to/projectA/.conda.Why it's a bug: The auto-assignment logic does not check whether the single env is actually inside the project being assigned. It blindly assigns to all projects. The
pathSorted.length > 1branch correctly checks project ownership viagetPythonProject(e.environmentPath), but the=== 1branch skips this check.Proposed fix: Only auto-assign when the env is inside the same project:
Bug 12 (Low-Medium): Step-based flow has broken regex for version sorting
File:
src/managers/conda/condaStepBasedFlow.ts, line 118What happens: The
parseMajorMinorfunction uses a double-escaped regex:In a JavaScript regex literal,
\\dmatches a literal backslash followed by the letterd— not a digit. The correct regex (as used in the identical function incondaUtils.tsline 998) is:Since the regex never matches version strings like
"3.13",parseMajorMinoralways returns{major: 0, minor: 0}. Thesort()comparator sees all items as equal, so versions appear in arbitrarySetiteration order rather than descending (3.13, 3.12, 3.11, ...).Repro steps:
Impact: This doesn't prevent selecting an environment, but it degrades UX and may cause users to pick the wrong version. The fallback list
['3.13', '3.12', '3.11', '3.10', '3.9']happens to be in correct order, but only triggers whenversions.length === 0(no envs discovered at all).Proposed fix: Fix the regex to use single backslashes:
Summary
condaEnvManager.tsset()global scope doesn't updateglobalEnvin memorycondaEnvManager.tsset()missing change events for global/single-UricondaUtils.tscondaUtils.tsenvPathcrash after named env creationcondaStepBasedFlow.ts+condaUtils.tscondaStepBasedFlow.ts+condaUtils.tscondaUtils.tsgetVersion()only finds Python 3.xcondaUtils.tscondaUtils.ts_runCondastderrcondaEnvManager.ts+condaUtils.tscondaEnvManager.tscondaStepBasedFlow.tsBugs 1, 3, and 10 are the most likely root causes of the reported "can't select certain conda environment" issues. Bug 1 causes global selections to silently revert. Bug 3 causes newly created environments on Linux/macOS to have non-functional Python executable paths. Bug 10 causes previous selections to be silently destroyed when users encounter and dismiss no-python environments.