Skip to content

Codex Desktop Remote SSH to Windows OpenSSH fails when default shell is PowerShell #22757

Open

Description

@omid-web

What version of the Codex App are you using?

Codex Desktop 26.513.20950 on macOS.

Remote Codex CLI observed:

  • Windows native Codex CLI: codex-cli 0.130.0-alpha.5
  • WSL/Linux Codex CLI workaround: codex-cli 0.130.0

What subscription do you have?

ChatGPT Pro

What platform is your computer?

Local client:

  • macOS on arm64
  • Codex Desktop app

Remote host:

  • Windows laptop over OpenSSH
  • Windows OpenSSH default shell set to PowerShell 7 (pwsh.exe)
  • Passwordless SSH key auth succeeds
  • Remote Windows workspace path: C:\MethodDev
  • codex app-server --help works when run manually in PowerShell

What issue are you seeing?

Codex Desktop Remote SSH discovers the Windows SSH host and authenticates successfully, but the connection fails during app-server bootstrap because the Desktop SSH transport sends POSIX login-shell bootstrap code to a PowerShell remote shell.

The failing remote command in app breadcrumbs includes a POSIX shell probe/exec shape like:

exec "$SHELL" -i -c '... if ( -r /etc/csh.login ) source ... exec /bin/sh -c "$CODEX_REMOTE_PAYLOAD" ...'

Because the remote OpenSSH login shell is PowerShell 7, PowerShell parses that POSIX/csh/sh syntax and fails with:

ParserError:
Line |
   1 | . ec "$SHELL" -i -c '\''set loginsh=1; if ( -r /etc/csh.login ) source ...
     |                                                               ~
     | Missing statement block after if ( condition ).

The Codex Desktop UI then reports the SSH connection as failed/reconnecting.

This appears related to shell compatibility issues such as #18183 and #19302, but this case is specifically native Windows OpenSSH with PowerShell as the configured default shell. In this setup, normal SSH and manual codex app-server invocation both work; the failure is the Desktop Remote SSH bootstrap assuming a POSIX-compatible login shell.

What steps can reproduce the bug?

  1. On a Windows machine, install OpenSSH Server and Codex CLI/Desktop.
  2. Configure Windows OpenSSH to use PowerShell 7 as the default shell, for example:
New-ItemProperty `
  -Path "HKLM:\SOFTWARE\OpenSSH" `
  -Name DefaultShell `
  -Value "C:\Program Files\PowerShell\7\pwsh.exe" `
  -PropertyType String `
  -Force
Restart-Service sshd
  1. From a Mac, verify SSH works and lands in PowerShell 7:
ssh windows-host '$PSVersionTable.PSVersion.ToString(); (Get-Location).Path; codex app-server --help'
  1. In Codex Desktop on macOS, add/select the SSH host under Settings -> Connections -> SSH.
  2. Enable the connection.
  3. Observe that the connection fails/retries.
  4. Inspect Codex Desktop breadcrumbs/logs; they show a PowerShell ParserError from the POSIX login-shell bootstrap.

What is the expected behavior?

Codex Desktop Remote SSH should support Windows OpenSSH hosts whose default shell is PowerShell, or at least fail with a clear diagnostic that the current Desktop Remote SSH bootstrap requires a POSIX-compatible shell.

A product-level fix could be one of:

  1. Detect PowerShell/Windows remote shells and use a PowerShell-native bootstrap path.
  2. Allow per-connection configuration of a bootstrap shell/command, so users can keep PowerShell as their interactive SSH shell while Codex uses an alternate shell for app-server startup.
  3. Detect unsupported shells before running POSIX syntax and show a clear actionable error.

Workaround

A WSL-backed SSH target works because it gives Codex a POSIX shell:

  • run an SSH server inside WSL on another port, e.g. 2222
  • connect Codex Desktop to that WSL SSH alias instead of the Windows OpenSSH alias
  • install Linux Codex CLI in WSL so codex app-server is on PATH
  • use /mnt/c/<workspace> for Windows project files
  • invoke Windows/IIS/PowerShell tools explicitly from WSL with pwsh.exe, powershell.exe, or cmd.exe

That workaround is usable, but it means native Windows OpenSSH + PowerShell is not a first-class Codex Desktop Remote SSH target today.

Activity

  1. omid-method commented on May 15, 2026

    @omid-method

    Adding a concrete repro from my Windows laptop / WSL-backed Codex Desktop setup, based on a live debugging session.

    Environment/context:

    • Codex Desktop is connected to the Windows laptop through the WSL workspace path /mnt/c/MethodDev.
    • The shell Codex gets is WSL Ubuntu (bash) on the Windows laptop, not native Windows PowerShell.
    • Files under C:\MethodDev are readable/writable through /mnt/c/MethodDev.
    • Windows tooling exists and is installed on the host:
      • PowerShell 7: C:\Program Files\PowerShell\7\pwsh.exe
      • Windows PowerShell: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
      • .NET: C:\Program Files\dotnet\dotnet.exe
      • Method CLI: C:\Users\Omid Rajabi\.dotnet\tools\mtd.exe

    What fails:

    From the Codex WSL shell, launching Windows executables through WSL interop fails before the target process can produce normal output.

    Minimal repro:

    '/mnt/c/Program Files/PowerShell/7/pwsh.exe' -NoProfile -Command '$PSVersionTable.PSVersion.ToString()'

    Observed output:

    <3>WSL (2 - ) ERROR: UtilBindVsockAnyPort:307: socket failed 1
    

    When retried through Codex's escalated command path, the process appeared to start but then exited with:

    <3>WSL (...) ERROR: UtilAcceptVsock:271: accept4 failed 110
    

    This is not specific to pwsh.exe. Similar attempts to launch Windows executables from the WSL-backed Codex session hit the same class of failure:

    '/mnt/c/Program Files/dotnet/dotnet.exe' ...
    '/mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe' ...
    '/mnt/c/Windows/System32/cmd.exe' /c ...
    '/mnt/c/Users/Omid Rajabi/.dotnet/tools/mtd.exe' ...

    Concrete workflow impact:

    I asked Codex to run the local Method workspace health check. The normal command is:

    cd C:\MethodDev
    mtd healthcheck run -a

    Inside the Codex WSL shell:

    • mtd was not on the Linux PATH.
    • Linux dotnet was not installed.
    • The Windows mtd.exe global tool was found at C:\Users\Omid Rajabi\.dotnet\tools\mtd.exe.
    • But invoking Windows mtd.exe, pwsh.exe, powershell.exe, cmd.exe, or dotnet.exe from Codex failed because WSL interop itself failed.

    Expected behavior:

    A WSL-backed Codex Desktop session on Windows should be able to invoke host Windows executables through normal WSL interop, especially for workflows where the repo lives under /mnt/c and local development depends on Windows-only tools such as IIS, PowerShell, Windows .NET, and locally installed CLIs.

    Actual behavior:

    Codex can read and edit the workspace under /mnt/c, but cannot cross the WSL-to-Windows process boundary. That blocks local Windows/IIS/PowerShell workflows from inside Codex even though the underlying tools are installed and should be callable from an ordinary WSL terminal.

    One additional note: trying to use the codex-work SSH alias from this WSL environment also failed with DNS/alias resolution:

    ssh: Could not resolve hostname codex-work: Temporary failure in name resolution
    

    So, in this setup, there was no working fallback from the Codex WSL session to native Windows execution.

  2. bookHsu-shinher commented on May 20, 2026

    @bookHsu-shinher

    Adding another anonymized repro from a Windows Codex Desktop host.

    Environment:

    • Local Codex Desktop on Windows: 26.513.4821.0
    • Local OpenSSH client/server: OpenSSH_for_Windows_9.5p2, LibreSSL 3.8.2
    • Remote target is the same Windows machine via local loopback OpenSSH (127.0.0.1:<non-default-port>)
    • Windows account is a domain account and local administrator; user/domain/hostname are redacted
    • Codex CLI on PATH inside SSH login shell: codex-cli 0.130.0
    • SSH public-key auth succeeds
    • sshd was restricted to loopback only for the repro

    What works outside Codex Desktop:

    ssh <redacted-host-alias>
    ssh <redacted-host-alias> 'codex --version'

    The second command returns:

    codex-cli 0.130.0
    

    What fails in Codex Desktop:

    Settings -> Connections -> SSH connections from this PC -> add/enable the Windows OpenSSH alias.

    After fixing key auth, the UI shows that SSH authentication succeeds:

    Authenticated to 127.0.0.1 ([127.0.0.1]:<redacted-port>) using "publickey".
    

    Then the connection still fails because the bootstrap appears to send POSIX/csh/sh login-shell probing code to a Windows shell. The UI error includes escaped/ANSI-contaminated output with fragments like:

    exec "$SHELL" -i -c 'set loginsh=1; if ( -r /etc/csh.login ) source ...'
    Missing statement block after if ( condition ).
    

    I tried both native Windows OpenSSH defaults and setting the OpenSSH default shell to PowerShell 7. The result is the same class of failure: SSH auth succeeds, but the remote bootstrap assumes POSIX shell semantics and PowerShell cannot parse the command.

    Additional notes:

    • This is not a key, firewall, or PATH issue: public-key auth works, the host is reachable, and codex --version works over the same SSH alias.
    • The confusing part for users is that the Codex Desktop UI only surfaces this as a generic SSH connection failure even though the failure is after successful authentication.
    • A clearer diagnostic would help, e.g. "Windows OpenSSH/PowerShell remote shells are not currently supported for Remote SSH; use WSL/Linux or configure a POSIX-compatible shell."

    This matches the original issue report: native Windows OpenSSH with PowerShell/cmd as the remote shell is not currently handled by the Codex Desktop Remote SSH bootstrap.

  3. mmiladinov commented on Jul 7, 2026

    @mmiladinov

    I am also seeing the same issue.

  4. dustovo commented on Jul 16, 2026

    @dustovo

    How to fix this issue?

    Codex Desktop version: 26.707.12708.0
    Remote OS: Windows
    Remote SSH server: Windows OpenSSH
    Remote default shell: PowerShell 7.6.3
    Failure stage: remote_codex_lookup
    Error type: AppServerSshSetupError

    SSH authentication succeeds and this works:

    ssh remote-server 'codex --version'
    codex-cli 0.144.5

    However, Codex Desktop sends a POSIX bootstrap payload beginning with:

    sh -c 'if [ -z "$SHELL" ] ...

    PowerShell then fails with:

    ParserError: Missing statement block after if ( condition ).

    The remote PATH, SSH key, Codex CLI, Node.js, and PowerShell configuration have all been verified working.

  5. eddy961206 commented on Aug 2, 2026

    @eddy961206

    same issue here

  6. TomaxMe commented on Aug 20, 2026

    @TomaxMe

    same issue here

  7. padeoe commented on Aug 20, 2026

    @padeoe

    same issue

  8. ShiTan-677 commented on Aug 21, 2026

    @ShiTan-677

    Adding an independent, anonymized reproduction from a macOS client to a native Windows OpenSSH host. This matches the same root cause with the Windows default cmd.exe shell (rather than PowerShell).

    Environment

    • Client: ChatGPT/Codex Desktop for macOS 26.803.61601 (build 6396)
    • Client OpenSSH: OpenSSH_10.2p1
    • Remote: Windows 11 Pro 10.0.26200.9168
    • Remote SSH server banner: OpenSSH_for_Windows_9.5
    • Remote Codex CLI: codex-cli 0.147.0
    • Remote account: standard (non-admin) Windows user
    • Authentication: public key
    • Remote OpenSSH default shell: native cmd.exe
    • The host is a concrete alias in ~/.ssh/config and was auto-discovered by Desktop; it was not manually entered in the app.

    Checks that succeed outside Desktop

    Using the same SSH alias and identity:

    ssh <alias>
    where codex
    C:\Users\<redacted>\Tools\Codex\bin\codex.exe
    
    codex --version
    codex-cli 0.147.0
    
    codex login status
    Logged in using ChatGPT
    

    The non-interactive app-server probe also succeeds:

    ssh <alias> "codex app-server --help"

    It prints the normal codex app-server help and exits successfully. The CLI lives in a normal NTFS directory (not the standalone installer's junction), so this is not a PATH or reparse-point failure.

    Desktop failure

    Desktop discovers the alias:

    hostId=remote-ssh-discovered:<alias>
    discoveredConnectionCount=1
    

    SSH authentication succeeds, and the client can see the Windows SSH implementation:

    Remote protocol version 2.0, remote software version OpenSSH_for_Windows_9.5
    Authenticated to <redacted-host> using "publickey".
    

    Immediately afterward, during the Codex path probe, Desktop sends a POSIX bootstrap to the native Windows shell:

    Sending command: sh -c 'if [ -z "$SHELL" ] || [ ! -x "$SHELL" ]; then ...
    case "${SHELL##*/}" in ...
    exec /bin/sh -c "$CODEX_REMOTE_PAYLOAD" ...
    if command -v codex >/dev/null 2>&1; then exit 0; fi'
    

    The Windows shell rejects it (the original localized output is mojibake in the app log; translated):

    'sh' is not recognized as an internal or external command
    '[' is not recognized as an internal or external command
    Exit status 255
    

    The final failure is:

    errorName=AppServerSshSetupError
    sshSetupStage=remote_codex_lookup
    operation=codex_path_probe
    

    So Desktop never reaches the already-working codex.exe or starts the app server.

    Expected behavior

    For a native Windows OpenSSH host, Desktop should select a Windows-native bootstrap (PowerShell or cmd-aware), locate codex.exe using the remote login shell's Windows PATH, and start the remote app server without requiring a machine-wide Git Bash default-shell override.

    The current official SSH workflow says that Desktop starts the remote Codex app server through SSH using the remote user's login shell and requires codex on that shell's PATH: https://learn.chatgpt.com/docs/remote-connections#connect-to-an-ssh-host

    This reproduction satisfies those prerequisites; the blocker is specifically the unconditional POSIX bootstrap at remote_codex_lookup.

  9. Pyromaniac6669 commented on Aug 23, 2026

    @Pyromaniac6669

    I am experiencing the same issue. SSH authentication and terminal access work, but the Codex Desktop SSH connection fails during bootstrap with a PowerShell parser error. I hope this can be fixed soon. Thank you!

  10. ken-jo commented on Sep 11, 2026

    @ken-jo

    Additional reproduction on Desktop 26.903.71938, with a proposed implementation and regression-test plan.

    Verified environment and failure boundary

    • Client: macOS, Codex Desktop 26.903.71938.
    • Target: native Windows OpenSSH, with PowerShell 7.6.5 as the configured login shell.
    • Remote CLI: codex-cli 0.147.0.
    • Public-key SSH authentication and an interactive PowerShell session succeed.
    • Running codex --version over the same SSH connection succeeds.
    • Desktop fails at remote_codex_lookup (the step that locates the remote Codex CLI), before successfully completing its CLI lookup/bootstrap.

    Minimal reproduction (the alias below is a placeholder):

    ssh windows-host 'codex --version'
    ssh windows-host '$PSVersionTable.PSVersion.ToString()'

    These return codex-cli 0.147.0 and 7.6.5. Enabling that SSH host in Desktop produces the failure described in this issue.

    Selected diagnostic fields, with identifiers and surrounding logs omitted:

    errorName=AppServerSshSetupError
    sshSetupStage=remote_codex_lookup
    ParserError
    Missing statement block after if ( condition ).
    

    The failed initialization command includes the Unix-shell branch set loginsh=1; if ( -r /etc/csh.login ) source .... The reported PowerShell parser error occurs while Desktop submits a command containing that Unix-shell syntax. This does not mean the target uses csh; the incompatible syntax is embedded in Desktop's login-shell wrapper.

    This narrows the observed failure to Desktop's remote initialization command selection. It does not establish whether later Windows app-server transport stages would work after this failure is fixed.

    Proposed implementation (not an implemented or validated patch)

    1. Separate platform discovery from bootstrap. Determine the remote OS and command interpreter before constructing a platform-specific payload. Honor an explicit per-connection platform/shell override first. Otherwise, try bounded, minimal executable probes with unambiguous arguments (for example, a PowerShell executable with a generated encoded payload that reports the runtime OS). Distinguish command-not-found from SSH/authentication failure, and request a platform selection when detection is inconclusive; an SSH banner alone is insufficient. Do not change the machine-wide OpenSSH default shell.
    2. Add a Windows bootstrap strategy alongside the POSIX strategy. For Windows, including a cmd default login shell, invoke a detected PowerShell executable with -NoLogo -NoProfile -NonInteractive. An explicitly generated UTF-16LE -EncodedCommand payload can reduce quoting problems, but executable discovery and the outer SSH command still require correct escaping and tests. Resolve the CLI in the effective remote environment, return a small structured result, and invoke the supported executable or launcher without assuming sh, nohup, pkill, $SHELL, or Unix paths. Preserve exit codes and impose timeouts.
    3. Validate transport separately. After lookup succeeds, negotiate a Windows-compatible app-server transport rather than assuming the existing Unix-socket path works. If supported by the existing server protocol, a candidate is loopback WebSocket with SSH local forwarding, using the app server's supported authentication and explicit process/port ownership. No public listener or unauthenticated shared endpoint should be needed. The later transport failure reported in Codex Desktop Remote SSH to native Windows host requires hidden CLI/Bash setup and still fails at app-server proxy #22965 is related evidence from another reporter, not a failure reproduced in this report.
    4. Classify deterministic setup failures. Report the stage, detected platform/shell, and an actionable explanation. Do not endlessly retry the same parse error. Cancel/reap bootstrap processes on timeout or disconnect and allow an explicit retry after configuration changes.

    Suggested acceptance tests

    • macOS client to native Windows with both PowerShell and cmd as the OpenSSH default shell; existing Linux/macOS SSH paths remain working.
    • CLI paths containing spaces and non-ASCII characters; supported executable/script launchers; missing CLI; non-interactive environment differences.
    • Full connection lifecycle: lookup, version check, server start, authenticated initialization, a harmless remote read, disconnect, and reconnect.
    • Syntax errors stop automatic retries; timeouts and cancellations leave no orphan bootstrap processes.
    • No machine-wide shell changes, public app-server exposure, or certificate-verification bypass.

    Happy to contribute additional sanitized reproduction details and test results in this issue, in line with the repository's contribution policy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingremote

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions