diff --git a/src/main/startup/hydrate-shell-path.test.ts b/src/main/startup/hydrate-shell-path.test.ts index d70441f6f5b..60c8dc0bd17 100644 --- a/src/main/startup/hydrate-shell-path.test.ts +++ b/src/main/startup/hydrate-shell-path.test.ts @@ -211,8 +211,10 @@ describe('hydrateShellPath', () => { }) it('overwrites the captured key in place so Windows never carries both Path and PATH', async () => { + vi.spyOn(process, 'platform', 'get').mockReturnValue('win32') const originalWindowsPath = process.env.Path delete process.env.PATH + process.env.PATH = 'C:\\Users\\u\\.nvm\\versions\\node\\v22.9.0\\bin;C:\\Windows' process.env.Path = 'C:\\Users\\u\\.nvm\\versions\\node\\v22.9.0\\bin;C:\\Windows' _setLaunchPathForTests('C:\\Windows', 'Path') diff --git a/src/main/startup/hydrate-shell-path.ts b/src/main/startup/hydrate-shell-path.ts index af1f7fbdb95..7804ee99743 100644 --- a/src/main/startup/hydrate-shell-path.ts +++ b/src/main/startup/hydrate-shell-path.ts @@ -121,11 +121,21 @@ function shellProbeEnv(): NodeJS.ProcessEnv { const key = launchPathOverride?.key ?? LAUNCH_PATH_KEY const value = launchPathOverride?.value ?? LAUNCH_PATH const env: NodeJS.ProcessEnv = { ...process.env, [PROBE_MARKER_ENV_VAR]: '1' } - if (value !== null) { - // Why the captured key, not a literal 'PATH': overwrite in place so Windows - // never ends up carrying both `Path` and `PATH` on the spawn env. - env[key] = value + if (value === null) { + return env } + if (process.platform === 'win32') { + // Why: the spread is a plain, case-sensitive object, but Windows resolves env + // names case-insensitively. Writing our key back without dropping the other + // casing leaves the seeded value live under `PATH` beside a clean `Path`, and + // the shell may read either one. + for (const name of Object.keys(env)) { + if (name !== key && name.toLowerCase() === key.toLowerCase()) { + delete env[name] + } + } + } + env[key] = value return env }