[Windows Desktop] Shell child processes get `PATHEXT` truncated to `.CPL`, causing `git`, `cmd`, and other `.exe` commands to stop resolving

Open 💬 4 comments Opened Mar 19, 2026 by STSNaive
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

What version of the Codex App are you using (From “About Codex” dialog)?

OpenAI Codex Desktop 26.313.5234.0 Windows Store package: OpenAI.Codex_26.313.5234.0_x64__2p2nqsd0c76g0

What subscription do you have?

Chatgpt Plus

What platform is your computer?

Microsoft Windows NT 10.0.22621.0 x64

What issue are you seeing?

Codex Desktop appears to launch some shell child processes with a corrupted PATHEXT.

Inside the broken shell process, the environment contains only:

$env:PATHEXT
.CPL

instead of a normal Windows value such as:

.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC

As a result, bare executable names stop resolving in PowerShell. For example:

  • git --version fails with CommandNotFoundException
  • cmd /c ... also fails if invoked without an explicit extension or full path
  • direct invocation with a full path still works, for example:
& 'C:\Program Files\Git\cmd\git.exe' --version

This breaks Codex shell tool calls on Windows whenever the tool tries to run git, cmd, or other .exe programs by name.

What steps can reproduce the bug?

  1. Open Codex Desktop on Windows.
  2. Start a workspace/thread.
  3. Ask Codex to run:
$env:PATHEXT
  1. Observe that inside the shell child process, it prints:
.CPL
  1. Ask Codex to run:
git --version
  1. Observe that it fails with CommandNotFoundException.
  2. Run:
& 'C:\Program Files\Git\cmd\git.exe' --version
  1. Observe that it succeeds.
  2. In the same broken shell, set:
$env:PATHEXT='.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC'
  1. Run again:
git --version
  1. Observe that it immediately starts working.

What is the expected behavior?

Codex should preserve the normal Windows PATHEXT value when spawning shell child processes, so bare .exe commands such as git, cmd, node, etc. resolve the same way they do in a normal PowerShell session.

Additional information

I did some local investigation to narrow this down:

  • Machine-level registry PATHEXT is normal
  • User-level registry does not override PATHEXT
  • My PowerShell profile does not modify PATHEXT
  • git.exe is installed and present on PATH
  • Direct full-path execution works
  • The parent Codex Desktop processes appear to have a normal PATHEXT
  • The corruption appears when app\resources\codex.exe (app-server --analytics-default-enabled) spawns the PowerShell shell child

My current inference is that the desktop app is rebuilding the child environment incorrectly and truncating PATHEXT to the last segment (.CPL).

View original on GitHub ↗

4 Comments

github-actions[bot] contributor · 5 months ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #14264

Powered by Codex Action

STSNaive · 5 months ago

Thanks for linking the similar issue, but I do not think my bug is the same one.

In my case, the problem is not that Git is missing, not that PATH is wrong, and not that PowerShell cannot launch external programs in general. The failure is specifically caused by the shell child process inheriting a corrupted PATHEXT value (.CPL only), which prevents bare .exe command names from resolving.

For example, when I try to invoke Git by name inside the broken Codex shell, I get:

git : The term 'git' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the s
pelling of the name, or if a path was included, verify that the path is correct and try again.
At line:2 char:1
+ git --version
+ ~~~
    + CategoryInfo          : ObjectNotFound: (git:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

However, this does not mean Git is absent. git.exe is installed, present on PATH, and can be launched successfully by full path. Also, if I restore PATHEXT inside the same broken shell to the normal Windows value, git --version immediately starts working again.

That behavior strongly suggests this is an environment-construction bug in the spawned shell process, specifically around PATHEXT, rather than the other reported issue.

iFTY-R · 4 months ago

~\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
~\Documents\PowerShell\Microsoft.PowerShell_profile.ps1

Microsoft.PowerShell_profile.ps1

function Set-MissingProcessEnv {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Name,
        [AllowNull()]
        [AllowEmptyString()]
        [string]$Value
    )

    if (-not [string]::IsNullOrWhiteSpace($Value) -and [string]::IsNullOrWhiteSpace([Environment]::GetEnvironmentVariable($Name, 'Process'))) {
        [Environment]::SetEnvironmentVariable($Name, $Value, 'Process')
    }
}

$systemDirectory = [Environment]::SystemDirectory
$windowsRoot = $null

if (-not [string]::IsNullOrWhiteSpace($systemDirectory)) {
    $windowsRoot = [System.IO.Path]::GetDirectoryName($systemDirectory)
}

if ([string]::IsNullOrWhiteSpace($windowsRoot)) {
    $windowsRoot = [Environment]::GetEnvironmentVariable('SystemRoot', 'Process')
}

if ([string]::IsNullOrWhiteSpace($windowsRoot)) {
    $windowsRoot = [Environment]::GetEnvironmentVariable('windir', 'Process')
}

if ([string]::IsNullOrWhiteSpace($windowsRoot)) {
    $windowsRoot = 'C:\Windows'
}

Set-MissingProcessEnv -Name 'SystemRoot' -Value $windowsRoot
Set-MissingProcessEnv -Name 'windir' -Value $windowsRoot
Set-MissingProcessEnv -Name 'ComSpec' -Value (Join-Path $windowsRoot 'System32\cmd.exe')
Set-MissingProcessEnv -Name 'SystemDrive' -Value ([System.IO.Path]::GetPathRoot($windowsRoot).TrimEnd('\'))

$userProfile = [Environment]::GetFolderPath([Environment+SpecialFolder]::UserProfile)
$appData = [Environment]::GetFolderPath([Environment+SpecialFolder]::ApplicationData)
$localAppData = [Environment]::GetFolderPath([Environment+SpecialFolder]::LocalApplicationData)
$programFiles = [Environment]::GetFolderPath([Environment+SpecialFolder]::ProgramFiles)
$programFilesX86 = [Environment]::GetFolderPath([Environment+SpecialFolder]::ProgramFilesX86)
$commonProgramFiles = [Environment]::GetFolderPath([Environment+SpecialFolder]::CommonProgramFiles)
$commonProgramFilesX86 = [Environment]::GetFolderPath([Environment+SpecialFolder]::CommonProgramFilesX86)
$programData = [Environment]::GetFolderPath([Environment+SpecialFolder]::CommonApplicationData)
$tempRoot = [System.IO.Path]::GetTempPath().TrimEnd('\')
$publicDir =
    if (-not [string]::IsNullOrWhiteSpace($userProfile)) {
        Join-Path ([System.IO.Path]::GetPathRoot($userProfile)) 'Users\Public'
    } else {
        'C:\Users\Public'
    }

Set-MissingProcessEnv -Name 'PUBLIC' -Value $publicDir
Set-MissingProcessEnv -Name 'USERPROFILE' -Value $userProfile
Set-MissingProcessEnv -Name 'APPDATA' -Value $appData
Set-MissingProcessEnv -Name 'LOCALAPPDATA' -Value $localAppData
Set-MissingProcessEnv -Name 'TEMP' -Value $tempRoot
Set-MissingProcessEnv -Name 'TMP' -Value $tempRoot
Set-MissingProcessEnv -Name 'ProgramFiles' -Value $programFiles
Set-MissingProcessEnv -Name 'ProgramFiles(x86)' -Value $programFilesX86
Set-MissingProcessEnv -Name 'ProgramW6432' -Value $programFiles
Set-MissingProcessEnv -Name 'CommonProgramFiles' -Value $commonProgramFiles
Set-MissingProcessEnv -Name 'CommonProgramFiles(x86)' -Value $commonProgramFilesX86
Set-MissingProcessEnv -Name 'CommonProgramW6432' -Value $commonProgramFiles
Set-MissingProcessEnv -Name 'ProgramData' -Value $programData
Set-MissingProcessEnv -Name 'OS' -Value 'Windows_NT'
Set-MissingProcessEnv -Name 'NUMBER_OF_PROCESSORS' -Value ([Environment]::ProcessorCount.ToString())

if (-not [string]::IsNullOrWhiteSpace($userProfile)) {
    Set-MissingProcessEnv -Name 'HOMEDRIVE' -Value ([System.IO.Path]::GetPathRoot($userProfile).TrimEnd('\'))
    $homePath = $userProfile.Substring(([System.IO.Path]::GetPathRoot($userProfile)).Length - 1)
    Set-MissingProcessEnv -Name 'HOMEPATH' -Value $homePath
}

$osArchitecture = $null

switch ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString()) {
    'X64' { $osArchitecture = 'AMD64' }
    'Arm64' { $osArchitecture = 'ARM64' }
    'X86' { $osArchitecture = 'x86' }
    'Arm' { $osArchitecture = 'ARM' }
}

Set-MissingProcessEnv -Name 'PROCESSOR_ARCHITECTURE' -Value $osArchitecture

$machineBackfillVars = @(
    'PROCESSOR_IDENTIFIER'
)

foreach ($name in $machineBackfillVars) {
    Set-MissingProcessEnv -Name $name -Value ([Environment]::GetEnvironmentVariable($name, 'Machine'))
}

$userBackfillVars = @(
    'OneDrive',
    'OneDriveConsumer',
    'NVM_HOME',
    'NVM_SYMLINK'
)

foreach ($name in $userBackfillVars) {
    Set-MissingProcessEnv -Name $name -Value ([Environment]::GetEnvironmentVariable($name, 'User'))
}

if ([string]::IsNullOrWhiteSpace([Environment]::GetEnvironmentVariable('Path', 'Process'))) {
    $pathParts = @(
        [Environment]::GetEnvironmentVariable('Path', 'Machine')
        [Environment]::GetEnvironmentVariable('Path', 'User')
    ) | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }

    if ($pathParts.Count -gt 0) {
        [Environment]::SetEnvironmentVariable('Path', ($pathParts -join ';'), 'Process')
    }
}

$requiredPathExt = @(
    '.COM',
    '.EXE',
    '.BAT',
    '.CMD',
    '.VBS',
    '.VBE',
    '.JS',
    '.JSE',
    '.WSF',
    '.WSH',
    '.MSC',
    '.RB',
    '.RBW',
    '.CPL'
)

$currentPathExt = @($env:PATHEXT -split ';' | Where-Object { -not [string]::IsNullOrWhiteSpace($_) })
$currentPathExt = $currentPathExt | ForEach-Object { $_.ToUpperInvariant() }
$hasExecutableExtensions =
    $currentPathExt -contains '.EXE' -and
    $currentPathExt -contains '.CMD' -and
    $currentPathExt -contains '.BAT'

if (-not $hasExecutableExtensions) {
    $seenPathExt = @{}
    $mergedPathExt = foreach ($ext in ($requiredPathExt + $currentPathExt)) {
        if (-not [string]::IsNullOrWhiteSpace($ext) -and -not $seenPathExt.ContainsKey($ext)) {
            $seenPathExt[$ext] = $true
            $ext
        }
    }

    [Environment]::SetEnvironmentVariable('PATHEXT', ($mergedPathExt -join ';'), 'Process')
}
whale7788 · 4 months ago

Confirmed. I had the same root cause: inside the broken shell, $env:PATHEXT was only .CPL, so PowerShell stopped resolving git -> git.exe.

Workaround that fixed it for me:
```powershell
[Environment]::SetEnvironmentVariable('PATHEXT','.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC','User')

And to auto-heal future PowerShell sessions, I added this to $PROFILE:

if (-not $env:PATHEXT -or $env:PATHEXT -notmatch '(^|;)\.EXE(;|$)') {
$fixedPathExt = '.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC'
$env:PATHEXT = $fixedPathExt
[Environment]::SetEnvironmentVariable('PATHEXT', $fixedPathExt, 'User')
}
```
That restored git --version and Get-Command git for me.