openai / openai/codex

Windows + WSL: independent failures in Linux helper isolation, project-root RPC conversion, and persisted thread cwd

Open
#44,918 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

app app-server bug session tool-calls windows-os
Dominant language
Rust
Stars
125k
Forks
19.4k
PR merge metrics
PR metrics pending

Description

I am opening this as a new issue because existing reports cover individual symptoms, while this local investigation adds concrete reproductions, code changes, and end-to-end validation. The failures share the Windows/WSL surface, but have independent first supported causes; this report does not claim one common root cause.

Live Desktop validation used Windows 11, WSL2 Ubuntu, Codex Desktop 26.903.9818.0, the WSL Agent Environment, and the codex-cli/app-server 0.154.0 line. One malformed persisted cwd still contained an older 26.903.8094.0 Appx resource path; that is historical stored data, not the live executable. User-specific paths below are redacted as <windows-user>, <linux-user>, and <codex-home>.

1. Patch 1: Linux arg0 helper isolation

In a Windows-backed shared Codex home, the Windows sidecar and the WSL/Linux runtime can use the same <codex-home>/tmp/arg0 directory while expecting different helper formats. Local evidence establishes a missing/unusable Linux helper as a pre-exec failure mode, but does not identify which historical process, if any, removed a particular helper. Related upstream reports show similar symptoms, but do not prove a cross-OS collision.

Failed to create unified exec process: No such file or directory (os error 2)

This is the helper lifecycle/missing-helper family described by #40583 and #27462. Those reports are related symptoms, not proof of the same deletion mechanism.

In arg0/src/lib.rs, the local candidate changes prepare_path_entry_for_codex_aliases so Linux uses <codex-home>/tmp/arg0-linux, while Windows remains on <codex-home>/tmp/arg0. The test creates a legacy janitor fixture under the legacy root; that fixture is removed, while the isolated Linux helper remains. Eight focused tests passed. The test unlocks the Linux helper before the janitor runs, so survival does not depend on a cross-OS lock being shared correctly. These are direct observations; the historical deletion actor remains unknown.

A later os error 2 occurred with the helper present; an explicit valid /tmp made it run, supporting a separate invalid-default-cwd cause. Not every os error 2 is therefore an arg0 failure.

2. Patch 2: WSL project creation/import/update rejects Windows and UNC roots

The practical consequence was that, because I could not add a project in WSL mode, I temporarily switched to Windows native mode to complete the add, then switched back to WSL mode.

While running that WSL-hosted project in Windows native mode, commands failed before launch with setup refresh had errors, which required switching back to WSL. Earlier diagnosis recorded Windows sandbox GetSecurityInfo and GetNamedSecurityInfoW returning 1; equivalent Get-Acl outside the sandbox also returned 1, while the directory was readable and the Windows NTFS control case succeeded. This is historical evidence, not a fresh reproduction, and does not show that either patch fixes Windows ACL or sandbox behavior.

With the Agent Environment set to WSL/Ubuntu, selecting a project through the Windows folder picker using a path such as:

\\wsl.localhost\Ubuntu\home\<linux-user>\repro

produced the generic UI error “Create project failed” and did not add the project. The app-server log exposed the underlying failure:

Local app-server project migration failed
AbsolutePathBuf deserialized without a base path

The smallest protocol-level reproduction is to send a Windows drive path or WSL UNC path in ProjectRoot.path to the WSL app-server. The Linux app-server rejects it at AbsolutePathBuf deserialization, before the project handler can create or update the project. The control input, an already-native path such as /home/<linux-user>/repro, is accepted by the same app-server path logic.

Expected behavior is to convert the picker representation to the selected WSL distribution’s native path before strict Linux path validation:

\\wsl.localhost\Ubuntu\home\<linux-user>\repro
    -> /home/<linux-user>/repro

Against source commit 6b9826e3aa83b1a5947db50f4332cb9c65f1b340, the local candidate changed app-server-protocol/src/protocol/v2/project.rs and app-server/src/request_processors/projects.rs, with focused coverage in app-server/tests/suite/v2/projects.rs. It reused the existing LegacyAppPathString representation and added one shared asynchronous conversion/validation path for project create, import, and update:

  • Native Linux absolute paths pass through unchanged.
  • On Linux with WSL_DISTRO_NAME, Windows drive paths and current-distro \\wsl$\<distro>\... or \\wsl.localhost\<distro>\... paths are converted with wslpath -u.
  • Relative paths, other distros, ordinary network shares, and a missing converter are rejected explicitly.
  • Existing strict AbsolutePathBuf, canonical-root, and duplicate checks run on the converted value before any store mutation.

Two focused Rust RPC tests and isolated stdio checks passed for create/import/update, native readback, duplicate rejection, unsupported-path rejection, and no-write behavior on conversion failure. The final runtime merged Patch 1 and Patch 2 and was started through the Desktop shortcut. In Desktop validation, local-project migration completed and selecting a WSL UNC directory succeeded. Root and child tasks ran without an explicitly supplied working directory; each pwd returned the expected native Linux project directory, and a child task completed and returned its native final result.

3. Separate one-time recovery for an existing thread cwd

The initial Desktop function that generated the malformed cwd was not identified; the affected persistence and recovery sources were identified instead.

Switching between Windows and WSL can leave an already existing thread with a mixed persisted cwd similar to:

/mnt/c/Program Files/WindowsApps/.../app/resources/C:\mnt\c\Users\<windows-user>\.codex

Without an explicit working directory, this state can independently produce os error 2. The value was present in the WSL thread database, the latest rollout settings event, and the Desktop thread catalog; changing only one field is insufficient because another source can win during resume.

For this one existing thread, I fully stopped Desktop, made consistent backups, appended a corrected settings event, and synchronized the matching metadata/catalog cwd to the intended WSL cwd. Old history was retained. After restarting, an implicit pwd returned the intended native cwd. This was a separate one-time offline repair; it was not part of either runtime patch.

This one-time recovery does not implement permanent cross-mode migration or rewrite other historical threads.

Related reports and request

The closest existing reports are:

  • #40583 and #27462: related Linux/Windows pre-exec and missing-helper symptoms; they do not prove the same collision or deletion mechanism.
  • #44507 and #44512: WSL project creation/migration failures involving AbsolutePathBuf deserialized without a base path.
  • #41746: a WSL UNC alias case where selecting \\wsl.localhost\... did not persist the project.
  • #42292: cross-environment thread cwd persistence and mismatch between session and stored cwd.
  • #30435: explicit working-directory behavior that can bypass a bad default cwd.
  • #44022: WSL project add/remove failures where a native restart restored the project; this is related symptom evidence only.
  • #44182: WSL switching with a mixed app/resources/C: path and related symlink/path-selection behavior; only the path portion is relevant here, not its separate image-access scope.
  • #44454: WSL project create/save failure, related as a symptom report only.

As of 2026-09-12, I found no linked upstream branch or released fix that covers these behaviors. Please consider whether the project-root conversion should live in the Desktop picker, the project-root wire contract, or at the WSL app-server boundary, and ensure migration plus project create/import/update use the same rules. For helper paths, the runtime/host ownership should be explicit so a helper cleanup path cannot remove or replace a Linux helper it does not own. For persisted threads, resuming an environment-switched thread should validate and repair the cwd namespace instead of replaying a mixed path.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with arg0/src/lib.rs, app-server-protocol/src/protocol/v2/project.rs, app-server/src/request_processors/projects.rs, and app-server/tests/suite/v2/projects.rs; read the existing path and helper lifecycle tests first. Done requires independently addressing Linux helper isolation, WSL project-root conversion for create/import/update, and persisted cwd recovery, with focused tests and end-to-end WSL validation showing native paths and working directories.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
backend-api-design, desktop-dev, operating-systems
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.