Codex desktop app on Windows injects split writable roots, causing `apply_patch` to fail before patching workspace files, forcing agents to fallback to bypass the sandbox and write files using powershell
What version of the Codex App are you using (From “About Codex” dialog)?
26.623.70822
What subscription do you have?
Pro
What platform is your computer?
Microsoft Windows NT 10.0.26100.0 x64
What issue are you seeing?
The safe edit path (apply_patch) is unusable in Codex desktop app sessions on Windows. Agents have to fall back to shell-based file rewrites inside the project, which bypasses the sandbox and is less precise and more error-prone.
The apply_patch tool call fails when patching files inside the active workspace root. The failure happens before the target file is read or modified.
Observed Error (according to agent)
apply_patch verification failed: Failed to read file to update C:\git\foobar\apps\server\src\routes\sync.ts:
failed to prepare fs sandbox:
failed to prepare windows sandbox wrapper:
windows unelevated restricted-token sandbox cannot enforce split writable root sets directly;
refusing to run unsandboxed
Observed Behavior
The desktop app provides a managed sandbox profile with multiple writable roots (C:\git\foobar and C:\tmp). On Windows, apply_patch cannot construct/enforce that split-root sandbox using the unelevated restricted-token backend, so it refuses to run at all.
What steps can reproduce the bug?
- Ensure workspace-write sandbox mode is enabled.
- Create a new session in
C:\git\foobar. - Send prompt
Create a test.txt file that says "hello world" - Observe the file is created.
- Send prompt
List the workspace roots added to this session, and also list all writable paths - Observe the only workspace root is
C:\git\foobarand writable paths areC:\git\foobar,C:\tmp,:tmpdir - Send prompt
Use theapply_patchtool to change "hello" intest.txtto "bye" - Observe agent responds with
I first triedapply_patch, but it failed because the Windows sandbox wrapper refused to run it in this restricted writable-root setup, so I made the same edit with PowerShell.
What is the expected behavior?
apply_patch should work for files inside the active writable workspace root, or the desktop app should not start Windows sessions with a sandbox shape that makes apply_patch unusable.
Additional information
The safe edit path (apply_patch) is unusable in Codex desktop app sessions on Windows. Agents have to fall back to shell-based file rewrites inside the project, which bypasses the sandbox and is less precise and more error-prone.
16 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Yeah, I'm still having this issue as of today. I've confirmed the issue is not present in the current IDE version of codex, only the windows app. I also checked older chat logs from a few weeks ago in codex and they were not having this issue, they were able to use apply_patch without errors.
I've got the same issue here when I use the codex VSCode extension.
Adding some diagnostics from my Windows setup.
Environment:
What I tried:
unelevatedandelevated.sandbox_private_desktop = false.exclude_tmpdir_env_var = trueandexclude_slash_tmp = true.Observed behavior:
sandbox = "unelevated":apply_patchadd works.apply_patchupdate/delete fails with:windows unelevated restricted-token sandbox cannot enforce split writable root sets directly; refusing to run unsandboxedsandbox = "elevated":apply_patchadd/update/delete works.CreateProcessAsUserW failed: 5sandbox_private_desktop = falsedid not change this.Wasted a bunch of tokens trying to get Sol to fix this until I found my way here. Please fix this..
I can independently reproduce this in Codex Desktop on native Windows.
Configuration:
The Desktop UI showed a single workspace root, but the managed permission profile still injected other writable locations, including temporary/runtime paths and paths previously available to the task.
Minimal test:
In one session, the patch failed before creation with:
Troubleshooting performed:
writable_rootsentry.A separate fresh-session test exhibited a closely related failure: the Add File patch succeeded, but deleting the same file through
apply_patchfailed withwindows_sandbox_helper_unknown_error. The file could then be removed through another filesystem operation. This second symptom appears to match #31229.The filename and patch body are ASCII-only and minimal. The failures occur during Windows sandbox preparation/ACL handling, before normal patch processing. This also encourages fallback to shell-based writes, bypassing the normal patch review workflow.
I can independently reproduce this on Codex Desktop for Windows with the unelevated sandbox.
Environment:
[windows] sandbox = "unelevated"Repro:
apply_patchAdd File inside the workspace succeeds.apply_patchUpdate File attempts against that existing file fail:0/5.apply_patchDelete File fails with the same error.Exact error:
I also tested the standalone Codex CLI directly in
workspace-writemode, without Desktop’s visualization root. Its effective writable roots were only:Add File still succeeded, but the first existing-file Update failed with the identical error. This shows the visualization root is not necessary to trigger the issue; the normal workspace-plus-temp root set is sufficient.
I removed legacy custom workspace/skill/plugin roots and fully restarted Desktop. I also disabled the Visualize plugin. Neither changed the failure. This is therefore not caused by user-configured roots, stale skill roots, the temporary arg0 launcher, or Visualize alone.
Security concern: in Desktop, harmless Add File probes outside the displayed writable roots were unexpectedly created, while existing-file Update/Delete fail closed. That leaves
apply_patchboth unreliable and inconsistent with the declared boundary.This appears to require a Codex Windows runtime fix. The unelevated restricted-token backend should support the effective split writable-root set, or the runtime should normalize/project its internal and temporary roots consistently before
apply_patchis invoked. A local config workaround that removes normal temp access or broadens filesystem access would not be an acceptable solution.@fcoury-oai Heads up that your merged Codex PR #31138 which was intended to fix this either didn't get merged into the new unified ChatGPT app, or it didn't resolve the issue.
This bug still persists, and 5.6 wastes even more time on working around it constantly (I frequently see the thinking text say
Planning a workaround for the sandbox apply_patch issue).There is now also an additional even worse case which is blocking development of one of my projects completely. After extended development, some corner-case issue has been hit, where apply_patch cannot be used and agents refuse to work around it even in new sessions. I'm assuming this is due to the new ChatGPT app having a stricter system prompt. Agents simply say
Blocked by the Codex patch helper: every apply_patch invocation fails because the WindowsApps executable returns “Access is denied,” including approved out-of-sandbox execution. No matter how much I've tried to get agents to bypass the sandbox restriction and use powershell for this project, they insist that their system prompt strictly prohibits bypassing the sandbox.Additional source-level evidence from
codex-cli 0.143.0and the current publicmainbranch.Observed source boundary
I reproduced the exact pre-file-access failure:
The installed 0.143.0 binary maps to tag
rust-v0.143.0, commitc4d748f586a84a3ed5b6aceb82e9a1db4abb1cda. The same refusal was still present when checked on publicmainat78ba047bdae3db0342dee11d8d9ef5582fe8ce49.The fail-closed check is in
codex-rs/sandboxing/src/windows.rs, functionresolve_windows_restricted_token_filesystem_overrides. It compares the compatibility projection writable roots with the requested split-policy roots and returns this diagnostic whenever the sets differ.The lower Windows sandbox already has much of the required representation:
WindowsSandboxFilesystemOverrides.write_roots_override--write-roots-jsonroot_capability_sidsHowever, the unelevated unified-exec branch does not forward
WindowsSandboxSessionRequest.write_roots_overrideintospawn_windows_sandbox_session_legacy. The capture path incodex-rs/core/src/exec.rssimilarly forwards the override only to the elevated backend.Two related fail-closed/atomicity gaps are relevant to a complete fix:
canonical_existingincodex-rs/windows-sandbox-rs/src/setup.rssilently removes nonexistent roots.apply_legacy_session_acl_rulesinspawn_prep.rssuppresses several allow/deny ACL errors, and the setup helper logs missing write roots as skipped.Reproduction detail
A named Add File probe succeeded once in the isolated official-source checkout. The immediately following built-in
apply_patchDelete File operation failed during sandbox preparation with the split-root diagnostic, before reading the probe. Shell and Git access continuing to work does not disprove this because those operations use a different launch path.Proposed enforcement contract
A complete launcher/policy fix should:
Windows CI should cover same-drive and cross-drive roots, spaces and Unicode, UNC, junction/reparse containment, alias deduplication, invalid-root partial failure and cleanup, shell plus built-in
apply_patchwrites in every declared root, and outside-root denial.This is a root-cause analysis and proposed acceptance contract, not a claim that the platform fix has been implemented or validated.
Additional reproduction from Codex Desktop on Windows, observed on 2026-07-22.
Environment
OpenAI.Codex_26.715.10079.0_x64__2p2nqsd0c76g0workspace-writewith restricted filesystem access:slash_tmp:tmpdirPrimary failure: built-in
apply_patchThe built-in patch tool failed before reading or modifying the target file:
This was not a malformed patch. The failure occurred while preparing the filesystem sandbox, before normal patch processing.
Approved escalation did not resolve it
The user explicitly approved running the operation outside the restricted sandbox. The generated wrapper resolved to:
Its contents invoked:
Invoking that underlying packaged executable through the approved escalation path still failed at Windows process launch:
The localized PowerShell error was
Zugriff verweigert.This second symptom matches #13959. That issue is closed as a duplicate, but current-version users have reported the same regression there. In this reproduction, the split-root sandbox refusal and the WindowsApps executable ACL failure occurred consecutively in the same task.
Control result
Using
git applywith an equivalent unified diff succeeded in the same workspace and task. The requested implementation and subsequent tests also completed successfully. This confirms:apply_patchsandbox/wrapper execution chain.Expected behavior
apply_patchshould update existing files within every declared writable root. If an approved out-of-sandbox retry is used, it should invoke an executable location that the approved PowerShell/tool process can actually execute, rather than the protectedWindowsAppspackage resource path.At minimum, the Desktop runtime should distinguish these two actionable failures:
A shell-based workaround exists, but it bypasses the normal patch tool workflow and should not be required for ordinary edits inside the selected workspace.
Confirmed again on a newer Codex Desktop build with the same failure mode.
Environment:
26.721.30844codex-cli 0.146.0-alpha.3codex-cli 0.118.0(not the runtime used by Desktop for this task)[windows] sandbox = "unelevated"E:\...C:\Users\<user>\.codex\visualizations\...The target source file is writable (
IsReadOnly=False), and its ACL grants Modify access to both the current account andCodexSandboxUsers. Nevertheless,apply_patchfails before modifying the target:This is especially confusing in Desktop because the second writable root is injected by Codex for visualization support; the user opened only the project workspace. The unrelated visualization root therefore prevents safe patching inside the valid project root.
Expected behavior:
apply_patchshould enforce and use the authorized target root even when another managed writable root is on a different volume, or Desktop should avoid passing an unsupported root topology to the unelevated Windows sandbox.Impact: normal cross-folder/multi-root workflows become unusable, and agents either abandon edits or attempt less-safe shell rewrites. The failure is reproducible on this current Desktop build/internal runtime, so #30712 remains active in practice.
Additional failure evidence from the same current Desktop environment: attempting the suggested approval/escalation path does not recover editing.
Observed sequence:
apply_patchis refused because the managed profile contains split writable roots.apply_patch.batunder the Codex WindowsApps installation.Access is denied, so the packaged patch helper still cannot start.This leaves a trusted and explicitly writable project root with no functioning built-in patch path: the unelevated wrapper rejects the root topology, while the escalated fallback cannot execute the packaged patch helper. The project root itself is not read-only and is not the denied target.
A valid direct
git apply/shell edit may still work as a manual fallback, but that bypasses the intended built-in safe patch path and requires agents to construct patches correctly. The Desktop runtime should provide an escalation route that invokes an accessible helper or brokers the patch operation without relying on a WindowsApps path that elevated child processes cannot execute.Another update from Codex Desktop on Windows, observed on 2026-07-24.
Environment:
26.721.31836I had been using Full access as a last-resort workaround for the Windows sandbox problems already documented in this issue:
elevatedsandbox mode, normal commands could not start becauseCreateProcessAsUserWfailed.unelevatedsandbox mode,apply_patchcould not reliably update existing files.Importantly, Full access had been working as expected for the past few weeks. During that time, Codex could carry out normal multi-step coding tasks without continuously requesting command approval. This behavior changed today, so it appears to be a recent regression rather than a configuration that never worked.
Starting today, even with Full access selected, Codex repeatedly asks me to approve commands—often roughly once per minute while an agent is working. This happens throughout ordinary multi-step coding tasks and requires constant supervision and interaction.
I have performed the usual troubleshooting steps, including completely restarting Codex Desktop and rebooting Windows. The behavior persists after both restarts.
Choosing the option to approve similar commands does not appear to solve the problem: Codex continues requesting approval for subsequent commands that are similar or equally innocuous.
As a result, all currently available modes are effectively impractical on my Windows installation:
apply_patch.Full access is already a significant security compromise that I accepted only because the safer Windows modes were not working. If it still requires approval at almost every step, it no longer provides a usable fallback and makes Codex Desktop nearly unusable for autonomous coding tasks.
Confirmation for genuinely high-impact or destructive commands would be completely reasonable. The current behavior, however, can require approving dozens or even hundreds of harmless steps during ordinary work. This creates approval fatigue and may actually reduce safety: after being trained to approve a constant stream of routine commands, a user is more likely to approve a genuinely destructive command mechanically without noticing the risk.
Approval prompts are only an effective safety measure when they are exceptional and meaningful. When nearly every step requires approval, they become both a serious usability problem and a potential safety problem in themselves.
Fresh reproduction on 2026-07-27 in Codex Desktop for Windows, package 26.721.4979.0 x64, managed workspace-write profile. Effective writable roots included the workspace, a per-task Codex visualization directory, :slash_tmp, and :tmpdir. Built-in apply_patch initially failed on an existing workspace file with: windows unelevated restricted-token sandbox cannot enforce split writable root sets directly; refusing to run unsandboxed. Retrying with a workspace-relative path failed identically, confirming the absolute Windows path was not the cause. In a later probe, apply_patch Add File inside the workspace succeeded, but the immediately following Delete File failed twice with the same split-root sandbox-preparation error. PowerShell removed the probe successfully. This confirms the failure remains present and can be operation-dependent/intermittent within one current Desktop task: Add may succeed while Update/Delete fail before reading the target. The fallback forces agents away from the required safe apply_patch workflow and into shell-based rewrites.
Root cause found, with a config-only workaround that most people can use today and a one-line runtime fix for @fcoury-oai or another OpenAI dev to make.
Workaround
On Windows this gives up nothing you actually had. The only access removed is
<drive>:\tmp, which was never deliberately granted.One comment above said they still had the issue with
exclude_slash_tmp = true, so that user either has a different unrelated issue that surfaces with the same error, or didn't put the config option under[sandbox_workspace_write].Root cause
The failure needs a writable-root set where the two sides of one comparison disagree. On Windows,
/tmpis the only entry that can disagree.FileSystemSandboxPolicy::workspace_write(protocol/src/permissions.rs) pushes aSlashTmpwrite entry wheneverexclude_slash_tmpis false (the default). There is no platform guard, so Windows profiles carry it too.resolve_file_system_special_pathviaAbsolutePathBuf::from_absolute_path("/tmp")./tmpis not absolute on Windows, so it absolutizes against the app server process's current drive and becomes<drive>:\tmp. It is kept if that directory exists.SandboxPolicy::WorkspaceWrite::get_writable_roots_with_cwd(protocol/src/protocol.rs), gates/tmpbehindcfg!(unix), so on Windows it never contributes a root.resolve_windows_restricted_token_filesystem_overrides(sandboxing/src/windows.rs) compares the two sets and fails closed when they differ.Instrumenting that comparison and running a failing patch prints:
:tmpdircannot cause this. Both sides resolve it from theTMPDIRenv var, which is normally unset on Windows, so it contributes nothing to either set. That matches the writable list in the original report —C:\git\foobar,C:\tmp,:tmpdir— where/tmpappears resolved and:tmpdirappears unresolved.Add File succeeds while Update/Delete fail because only the latter pre-read the target through the fs-sandbox helper. Hence
Failed to read file to update ....Why some people cannot reproduce it
The divergence exists only when
<drive>:\tmpexists on the drive the app server runs from. Nothing in Codex creates it. Pointing the app server's process cwd at a drive with no\tmpmakes the identical scenario pass with the stock Desktop binary.Anyone who sees
C:\tmpin their writable-roots list is by definition affected, since:slash_tmponly resolves when the directory exists.Ruled out
Each tested against a build instrumented to dump both sets, with
exclude_slash_tmp=trueso/tmpcould not mask the result. All produced identical sets and passed:| candidate | result |
| --- | --- |
| extra writable root that exists | no divergence |
| extra writable root that does not exist | no divergence |
| multiple runtime workspace roots (the injected-root shape) | no divergence |
| workspace reached through an NTFS junction | no divergence |
| lowercase drive letter in
cwd| no divergence ||
TMPDIRset explicitly | no divergence — present on both sides |Multi-root configurations stay symmetric because
ProjectRootsis materialized into concrete path entries before the check. So "split writable roots" in the sense of several roots was never the trigger; the trigger is one root that only one side produces.Fix
resolve_file_system_special_pathis the right place because it is the single choke point both sides go through. Fixing onlyworkspace_writewould miss profiles whose entries are supplied rather than derived.cfg!(unix)leaves Unix behaviour byte-identical. Built fromrust-v0.146.0-alpha.3.1and frommain(e8f0f64f20): the repro goes fromfailing every time to passing 3/3, and
codex-protocol(252),codex-sandboxing(37) and thecodex-coreWindows tests (54) stay green.Aside: why this was hard to diagnose
app-server/src/lib.rswraps state/sandbox failures withstd::io::Error::other(format!("...: {err}")), which keeps only the outermost context and drops the underlying cause. Several unrelated failures surface as a single opaque line with no way to recover the real error without a source build.Thanks to https://github.com/openai/codex/issues/30712#issuecomment-5098495052, I was able to finally chase down the fix. I also initially thought it was the .visualizations writable root, but it was a red herring. I independently confirmed the
/tmppolicy-mismatch diagnosis and found an additional Codex Desktop configuration-precedence issue that explains why the suggested workaround may initially appear ineffective.Environment:
26.721.11231[windows] sandbox = "unelevated"C:\tmpexistsTEMP/TMPpoint to the user-profile temp directoryTMPDIRis unsetOriginal behavior using native
apply_patch:Exact error:
The per-task
.codex\visualizations\...writable root is not the cause. After fixing the/tmpmismatch, tasks retained one or more visualization roots and native create/update/delete all succeeded.I first added only:
After fully restarting Desktop and creating a fresh task, the effective recorded policy still contained:
Update and delete therefore continued failing with the same error. The global setting existed but was not active because Desktop was selecting its newer managed permission-profile path. OpenAI’s documentation notes that permission profiles do not compose with the older
sandbox_mode/[sandbox_workspace_write]configuration path.The working global configuration was:
After another full restart, a completely fresh task—with no project-level
.codex/config.toml—recorded:The effective permissions no longer contained
:slash_tmp. The workspace,:tmpdir, and injected visualization roots remained writable.Three separate native
apply_patchcalls then:All three succeeded. No shell fallback was used and no probe remained.
This suggests two related product fixes:
SlashTmpas Unix-only when resolving filesystem special paths on Windows.sandbox_workspace_write.exclude_slash_tmpor clearly communicates that the setting is inactive unlesssandbox_mode = "workspace-write"selects the older configuration path.Deleting
C:\tmpwould also make the mismatched root disappear, but that is brittle because another tool can recreate the directory. The explicit exclusion is the durable workaround.