Skip to content

Bug: registerNoConfigDebug corrupts terminal PATH by missing semicolon separator on Windows #986

@lihanspace

Description

@lihanspace

Bug: registerNoConfigDebug corrupts terminal PATH by missing semicolon separator on Windows

Environment

  • OS: Windows 11 Pro
  • VS Code: latest stable
  • ms-python.debugpy extension version: 2025.18.0
  • Other relevant extensions: ms-dotnettools.vscode-dotnet-runtime 3.0.0

Description

The registerNoConfigDebug function appends the noConfigScripts directory to the terminal PATH via EnvironmentVariableCollection.append(), but it decides whether to prepend a ; separator by checking process.env.PATH in the extension host process rather than the terminal's actual PATH. When process.env.PATH in the extension host ends with ; (e.g. because another extension like ms-dotnettools.vscode-dotnet-runtime modifies it directly via process.env.PATH += delimiter + path), the separator is omitted, corrupting the terminal PATH.

Steps to Reproduce

  1. Install ms-python.debugpy alongside an extension that directly mutates process.env.PATH in the extension host (e.g. ms-dotnettools.vscode-dotnet-runtime).
  2. Ensure the user PATH contains entries like C:\Users\<user>\.local\bin near the end.
  3. Open a new integrated terminal in VS Code.
  4. Run: $env:Path -split ';' | Select-String '\.local\\bin'

Expected Behavior

C:\Users\<user>\.local\bin

Each PATH entry is properly separated by ;.

Actual Behavior

C:\Users\<user>\.local\binc:\Users\<user>\.vscode\extensions\ms-python.debugpy-2025.18.0-win32-x64\bundled\scripts\noConfigScripts

The two paths are concatenated without a ; separator, making both entries unresolvable. Any executable in .local\bin (e.g. claude) becomes unavailable in the VS Code terminal while working fine in a standalone terminal.

Root Cause

In src/extension/noConfigDebugger/noConfigDebugAdapter.ts (minified in dist/extension.js):

const noConfigPath = path.join(extensionPath, "bundled", "scripts", "noConfigScripts");
const delimiter = process.platform === "win32" ? ";" : ":";
const currentPath = process.env.PATH || "";
const value = currentPath.length > 0 && !currentPath.endsWith(delimiter)
    ? `${delimiter}${noConfigPath}`
    : noConfigPath;
collection.append("PATH", value);

The issue is that process.env.PATH reflects the extension host process environment, which can be modified by other extensions at runtime (e.g. process.env.PATH += ";" + somePath). However, EnvironmentVariableCollection.append() operates on the terminal environment, which is constructed independently by VS Code from the system/user PATH plus all extensions' EnvironmentVariableCollection mutations.

When the extension host's process.env.PATH happens to end with ; (due to another extension's direct mutation), the condition !currentPath.endsWith(delimiter) evaluates to false, so the delimiter is omitted. But the terminal's actual PATH does not end with ;, resulting in a corrupted concatenation.

Suggested Fix

Always prepend the delimiter when appending, since EnvironmentVariableCollection.append() performs raw string concatenation:

const value = `${delimiter}${noConfigPath}`;
collection.append("PATH", value);

This is safe even if the terminal PATH already ends with ; — it would just produce an empty entry (;;), which is harmless and is the standard defensive practice for PATH manipulation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    triage-neededNeeds assignment to the proper sub-team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions