[WSL] Resumed sessions get a lowercased /mnt cwd from the state DB, breaking project trust and approval matching
Open 💬 1 comment Opened Aug 14, 2026 by scmmm
What version of Codex CLI is running?
0.147.0
What subscription do you have?
plus
Which model were you using?
_No response_
What platform is your computer?
_No response_
What terminal emulator and version are you using (if applicable)?
_No response_
Codex doctor report
What issue are you seeing?
On WSL2, when a project lives on a Windows drive mounted under /mnt/<drive> and the path contains mixed-case components, every resumed session restores an all-lowercased cwd. For example, the original cwd /mnt/m/2026/TesT becomes /mnt/m/2026/test after resume.
This is not just cosmetic — it breaks permission management:
- Project trust is lost.
~/.codex/config.tomlstores trusted projects keyed by the original-case path ([projects."/mnt/m/2026/TesT"] trust_level = "trusted"), but the resumed session's cwd is lowercasetest, so the trust lookup misses. The trust screen is shown again and project-local config / hooks / exec policies are treated as untrusted. - Commands require approval every time. Path-based access checks compare against workspace roots / recorded paths that still carry the original casing, so they no longer match. Commands that previously ran without prompting now ask for approval — even though on the drvfs mount
testandTesTresolve to the same directory.
<img width="1211" height="843" alt="Image" src="https://github.com/user-attachments/assets/4f7f0a2b-187b-403f-b705-9a6951fc8e9d" />
<img width="1106" height="843" alt="Image" src="https://github.com/user-attachments/assets/2c198809-c690-4998-86e0-cfbae22df63b" />
What steps can reproduce the bug?
- On WSL2 create a mixed-case dir on a Windows drive:
mkdir -p /mnt/<drive>/path/TesT && cd /mnt/<drive>/path/TesT - Start
codex, send any message, and trust the project when prompted (writes the original-case key intoconfig.toml). Let a command get approved/run. /newin the same window.- Exit, then resume the session (
codex resumeor/resume).
What is the expected behavior?
_No response_
Additional information
I successfully fixed this issue at https://github.com/scmmm/codex/tree/fix/wsl-resume-cwd-case.
1 Comment
Traced this on
main@ 1f41cc5d92 — the lowercasing and the trust break are two halves of one asymmetry: a comparison normalization is being persisted as an identity value, while the stored trust keys never get the same normalization.Where the lowercase comes from.
normalize_for_path_comparisoncanonicalizes and then, on WSL, ASCII-lowercases any/mnt/<drive>/...path (codex-rs/utils/path-utils/src/lib.rs#L148-L211—normalize_for_wsl_with_flag→lower_ascii_path). That's a reasonable comparison key for a case-insensitive drvfs mount. The problem is that the thread stores persist it as the thread's actual cwd:normalize_cwd_for_state_db)normalize_cwd)So resume restores
/mnt/m/2026/testas the working cwd — the comparison key has leaked into identity.Why trust lookup then misses, precisely. The project-trust lookup builds candidate keys from the query path — the raw string plus its comparison-normalized form — but the stored
[projects."..."]keys are only lowercased undercfg!(windows), which is false in a WSL (Linux) binary:https://github.com/openai/codex/blob/1f41cc5d92722748e45cae9cecc6d883a4e7cbb1/codex-rs/config/src/config_toml.rs#L841-L862
Walk it through: in the original session, cwd
/mnt/m/2026/TesTproduces keys["/mnt/m/2026/test", "/mnt/m/2026/TesT"], and the second one hits the stored key → trusted. After resume the cwd is already lowercased, so the candidate set collapses to["/mnt/m/2026/test"]— and the storedTesTkey is never normalized on the map side → miss → trust screen again. The same one-sided normalization explains the approval/workspace-root mismatches.Fix shape. Two independent corrections, both worth doing:
normalize_for_path_comparisononly at compare time (or in a dedicated lookup column). This fixes resume cwd, approval matching, and the cosmetic path in one move. @scmmm's branch (fix/wsl-resume-cwd-case, touchingrollout/src/recorder.rs,thread-store/src/local/read_thread.rs,tui/src/session_resume.rs) looks like this shape — preserving the original casing through record/read/resume.normalize_project_lookup_keyshould apply the same WSL-aware comparison normalization to the stored keys thatnormalized_project_lookup_keysapplies to the query (today it lowercases only undercfg!(windows)). With both sides normalized, either casing of the same drvfs directory resolves to the same trust entry, which also retroactively repairs configs that already contain mixed-case keys — fix (1) alone leaves previously-lowercased DB rows failing against mixed-case trust keys.A regression test can stay entirely on Linux CI by driving the
_with_flagvariants (normalize_for_wsl_with_flag(path, /*is_wsl*/ true)) — no WSL environment needed: assert that a/mnt/m/…/TesTcwd round-trips through persist→resume with case preserved, and that trust lookup matches in both directions with a mixed-case stored key.