Skip to content

Spreading {...env, PATH} leaves the old Path sitting next to it

env paths · case

bothsilentscriptagentfirst-partyrepro: verifiedenv-casing
Affectsnode, windows, win32 api
Fails assilent
Mechanismenv casing
Safe fixenv remerge

JS code overrides PATH for a child process: {...process.env, PATH: shimDir}. On Windows the child sometimes resolves tools from the ORIGINAL path anyway — the shim directory is ignored, intermittently, depending on which library reads the env.

// Windows: process.env has key "Path" (registry casing)
const env = { ...process.env, PATH: "C:\\shims" };
// env now has BOTH "Path" (inherited) and "PATH" (yours).
// Consumers reading env.Path, or iterating keys first-match, use the old list.

Windows environment variable NAMES are case-insensitive, but JS objects are case-sensitive. The inherited key is usually Path; adding PATH creates a duplicate rather than replacing it. Which one wins depends on the consumer — CreateProcess dedupes one way, Node libraries another.

  • Find the existing key case-insensitively and overwrite THAT key: const k = Object.keys(env).find(x => x.toUpperCase()==="PATH") ?? "PATH".
  • Never introduce a second casing into a copied env (the referenced fix’s lookup() does exactly this).