Skip to content

[bug] Codex launcher cannot start on native Windows #440

Description

@wellorbetter

Symptom

switchyard launch codex from the published v0.2.0 Windows wheel crashes before the native proxy or Codex starts. The launcher imports the POSIX-only ShellTUI unconditionally, which imports fcntl on native Windows.

While validating the full startup path, three follow-on Windows blockers were also reproducible: the npm extensionless shim is selected instead of codex.cmd, Codex's UTF-8 model catalog is decoded with the active Windows code page, and a configured system proxy can intercept the loopback proxy URL inherited by Codex.

Reproduction

In a clean PowerShell session:

py -3.12 -m venv .venv
.\.venv\Scripts\python.exe -m pip install "nemo-switchyard[cli,server]==0.2.0"
npm install -g @openai/codex
.\.venv\Scripts\switchyard.exe launch codex --model switchyard

No provider request is made and no API key is required to reach the failure; it happens while dispatching the Codex launcher.

Published-wheel traceback, with the local environment path redacted:

Traceback (most recent call last):
  File "<venv>\Scripts\switchyard.exe\__main__.py", line 7, in <module>
  File "<venv>\Lib\site-packages\switchyard\cli\switchyard_cli.py", line 157, in main
    args.func(args)
  File "<venv>\Lib\site-packages\switchyard\cli\launch_command.py", line 37, in cmd_launch_codex
    from switchyard.cli.launchers.codex_cli_launcher import launch_codex_config
  File "<venv>\Lib\site-packages\switchyard\cli\launchers\codex_cli_launcher.py", line 33, in <module>
    from switchyard.server.shell_tui import ShellTUI
  File "<venv>\Lib\site-packages\switchyard\server\shell_tui.py", line 21, in <module>
    import fcntl
ModuleNotFoundError: No module named 'fcntl'

Forcing UTF-8 does not change this first failure:

PYTHONUTF8=1
preferred_encoding=utf-8
ModuleNotFoundError: No module named 'fcntl'

After locally bypassing the POSIX TUI import to continue the same startup path:

shutil.which("codex") -> <npm-prefix>\codex
OSError: [WinError 193] %1 is not a valid Win32 application

The sibling Windows shim works:

shutil.which("codex.cmd") -> <npm-prefix>\codex.cmd
codex-cli 0.147.0

The next catalog read fails under the default cp936 locale because subprocess.check_output(..., text=True) uses the active code page for Codex's UTF-8 JSON:

UnicodeDecodeError: 'gbk' codec can't decode byte 0x9d

Expected vs. actual

  • Expected: The Codex launcher should start on native Windows, inherit the current console instead of using the POSIX PTY footer, resolve the launchable npm shim, and connect Codex to the loopback Switchyard proxy.
  • Actual: The published Windows wheel crashes at import time on fcntl; bypassing that reveals the npm shim and model-catalog decoding failures above.

Environment

  • Switchyard version (or commit SHA): nemo-switchyard==0.2.0, official cp312-abi3-win_amd64 wheel from the v0.2.0 release
  • Python version (python --version): Python 3.12.0
  • OS / arch: Windows 11 Pro 10.0.26200, x86-64
  • Install path (uv sync, pip install nemo-switchyard, source build, etc.): clean virtual environment, pip install "nemo-switchyard[cli,server]==0.2.0"
  • Inbound format (Chat Completions / Anthropic Messages / Responses): Responses (Codex CLI)
  • Backend (OpenAI / Anthropic / NVIDIA Inference Hub / other): not reached by the initial reproduction; end-to-end validation used an OpenAI-compatible endpoint
  • Codex version: codex-cli 0.147.0, installed with npm

Additional context

The release publishes Windows wheels and the package installs successfully; the failure is specific to the coding-agent launcher path. switchyard launch codex --help also succeeds because argparse exits before dispatch imports the launcher, so it does not exercise this failure.

A focused fix can keep the existing ShellTUI behavior on POSIX, use the inherited console on Windows, select the sibling codex.cmd created by npm, decode the bundled catalog explicitly as UTF-8, and preserve loopback hosts in the child process's NO_PROXY environment.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions