macOS 0.122.0: apply_patch hangs under workspace-write but succeeds under danger-full-access

Open 💬 8 comments Opened Apr 22, 2026 by andrewalex
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

Summary

On macOS ARM64 with codex-cli 0.122.0, the internal apply_patch tool can hang indefinitely under the normal sandboxed path (workspace-write / --full-auto) on a tiny local file.

The same exact patch succeeds immediately when the nested Codex run uses --dangerously-bypass-approvals-and-sandbox (danger-full-access).

This looks distinct from #17834:

  • #17834 is the earlier macOS 0.120.0 case where apply_patch returned a ~10s timeout with exit code 124
  • this report is the newer 0.122.0 case where apply_patch is dispatched but then produces no success or error until interrupted/killed

Environment

  • OS: macOS 26.3.1 (build 25D771280a)
  • Arch: arm64
  • Codex CLI: codex-cli 0.122.0

Minimal repro

mkdir -p /tmp/codex-test
printf 'one\ntwo\n' > /tmp/codex-test/test.txt

Interactive repro:

cd /tmp/codex-test
codex

Then ask Codex:

use apply_patch to change "two" to "three" in test.txt

Non-interactive repro for the same sandboxed path:

codex exec --json --full-auto --skip-git-repo-check --cd /tmp/codex-test \
  'use apply_patch to change "two" to "three" in test.txt'

Observed behavior under workspace-write

Codex reads test.txt, emits the apply_patch tool call for the expected one-line diff, and then nothing comes back from the tool path.

The patch used was:

*** Begin Patch
*** Update File: test.txt
@@
-two
+three
*** End Patch

Observed outcome:

  • no success output
  • no parse error
  • no deterministic tool error
  • file remains unchanged
  • the session only ends after manual interrupt or an external timeout wrapper kills the run

In a fresh batch I ran the same --full-auto repro 5 times with an outer 45-second wrapper. Results:

  • 0/5 succeeded
  • 5/5 hung until killed by the wrapper
  • 5/5 left test.txt unchanged as:
one
two

Comparison against danger-full-access

Running the same repro with:

codex exec --json --dangerously-bypass-approvals-and-sandbox --skip-git-repo-check --cd /tmp/codex-test \
  'use apply_patch to change "two" to "three" in test.txt'

succeeded immediately with normal tool output:

Success. Updated the following files:
M /tmp/codex-test/test.txt

and the file became:

one
three

Why this seems important

This strongly suggests the problem is in the sandboxed filesystem / helper path used by apply_patch, not in the patch text itself. That is an inference from the behavior above, not a confirmed root cause.

Expected behavior

The same minimal patch should either:

  • succeed normally under workspace-write, or
  • fail quickly with a deterministic tool error

It should not hang indefinitely on a 2-line local file.

Related

  • Related but distinct: #17834

If useful, I can provide redacted session JSONL excerpts showing the workspace-write hang and the danger-full-access success.

View original on GitHub ↗

8 Comments

github-actions[bot] contributor · 4 months ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #17834

Powered by Codex Action

andrewalex · 4 months ago

Follow-up data point from the same minimal /tmp/codex-test repro on the same machine.

I reran the nested danger-full-access / --dangerously-bypass-approvals-and-sandbox path 5 more times with the same patch and a 45-second outer wrapper.

Results:

  • 5/5 succeeded
  • 0/5 hung
  • 5/5 changed test.txt from:
one
two

to:

one
three

Durations were roughly 17-21 seconds per run.

So the current local split is:

  • workspace-write: 0/5 success, 5/5 hang
  • danger-full-access: 5/5 success, 0/5 hang

That still points at the sandboxed path as the differentiator rather than the patch text itself.

etraut-openai contributor · 4 months ago

Do you have reason to believe that this behavior changed recently? I'm trying to determine if it's a regression.

andrewalex · 4 months ago
Do you have reason to believe that this behavior changed recently? I'm trying to determine if it's a regression.

Good question. On April 14th, I'd primarily get timeouts (Issue #17834) now I get complete hangs, so I'd say it's gotten worse and its become more predictable.

etraut-openai contributor · 4 months ago

We haven't had other reports of #17834 or this issue, so I'm wondering if this is something that's specific to your machine. It's unlikely we'll be able to prioritize an investigation unless this is reported by other users. Since codex is open source, you could clone the repo and work with Codex to try to identify a root cause.

andrewalex · 4 months ago

I found two concrete issues in the macOS sandboxed fs-helper path:

  1. In codex-rs/utils/absolute-path/src/lib.rs, AbsolutePathBuf was calling home_dir() even for ordinary absolute paths like /tmp/.... That should only happen for ~ paths.
  2. In codex-rs/exec-server/src/fs_sandbox.rs, the fs-helper is launched with env_clear() and a very small allowlist, which drops __CF_USER_TEXT_ENCODING on macOS.

__CF_USER_TEXT_ENCODING is a private macOS/CoreFoundation env var associated with per-user text encoding state (~/.CFUserTextEncoding`).

In the sampled blocked stacks, both of those led into the same Apple fallback path (getpwuid_r -> notify_register_check -> bootstrap_look_up2) inside the sandboxed fs-helper. That helper path is not used under YOLO, which explains why it works. On my machine, that fallback path can block. On other machines it may return quickly, which would explain why this can be a real code-level bug but still only show up for one reporter so far.

I patched both locally:

  • preserve __CF_USER_TEXT_ENCODING for the macOS fs-helper
  • skip home_dir() lookup unless the path actually starts with ~

I also added regression coverage for the non-~ path case.

I couldn’t open a PR because this repo currently restricts PR creation, but I pushed a branch to my fork in case its useful.

andrewalex · 4 months ago

@etraut-openai Any chance we can get this fix into an upcoming version? Both changes are contained and quality improvements on their own even without this bug

Cubatica · 23 days ago

Independent data point from a second reporter, plus a re-test on a current release.

We run Codex non-interactively in automated build workers on macOS, where apply_patch writing multi-line files is the hot path. Back in July we hit exactly the symptom described here and shipped a workaround that force-upgrades --sandbox workspace-write to danger-full-access for our build workers.

Our July reproduction (codex-cli 0.142.5, macOS, Intel x86_64): a ~150-line single-file apply_patch hung 3/3 under --sandbox workspace-write and succeeded 3/3 in ~34s under danger-full-access. Same split reported here.

Re-test today on codex-cli 0.146.0, same machine (macOS 24.6.0, Intel Core i9, x86_64):

| sandbox mode | result | wall clock | sandboxed fs-helper observed |
|---|---|---|---|
| workspace-write | 3/3 success | 60.6s / 65.0s / 67.8s | yes (1 helper per run) |
| danger-full-access | 3/3 success | 59.3s / 58.7s / 66.5s | no |

Method: a throwaway git repo under /tmp per run, codex exec --sandbox <mode> --json --skip-git-repo-check, prompt instructing a single apply_patch call that creates a 150-line file, 120s hard timeout with process-group kill (the original failure hung indefinitely, so a timeout is the hang detector). Each run was verified to have actually taken the patch path: the JSONL shows file_change going item.started -> item.completed, no shell/command fallback, and the resulting file has exactly 150 lines. The helper column matters as a control: ps shows a --codex-run-as-fs-helper child during every workspace-write run and none under danger-full-access, so the sandboxed helper path really was exercised rather than silently skipped.

So: no longer reproducible for us on 0.146.0. The workspace-write timings are now indistinguishable from danger-full-access.

One correction to our own earlier evidence that may be worth recording here, since it cuts against a simple "fixed in a later release" reading. #25118 ("exec-server: preserve fs helper CoreFoundation env", the __CF_USER_TEXT_ENCODING fix) merged 2026-05-29 and is an ancestor of rust-v0.142.5 — the exact version we were on when we saw the hang in July. So our July failure happened with that fix already present. Either our July hang had a second contributing cause (we were separately dealing with leaked --codex-run-as-fs-helper orphans from SIGKILLed runs, which is a plausible confound on our side), or the remaining trigger is intermittent and environment-sensitive in the way @andrewalex and #24956 both describe. We can't cleanly separate those from here, so we're reporting it as "not reproducible on 0.146.0" rather than "confirmed fixed by a specific commit".

Two things that might still be worth maintainer attention:

  1. @andrewalex's root-cause analysis in this comment identified two separate defects, and the second one — AbsolutePathBuf calling home_dir() even for ordinary absolute paths that don't start with ~ — appears to have landed since (current codex-rs/utils/absolute-path/src/lib.rs guards the lookup behind a ~ prefix check). Worth confirming that's intentional coverage of their report rather than an incidental change, since they noted they couldn't open a PR because the repo restricts PR creation and pushed a branch to their fork instead. If their regression tests aren't upstream, they'd be cheap insurance against this class recurring.
  1. #24956 ("[sandboxing] Prevent macOS fs-helper startup hangs"), which was marked Fixes #19020 and carried a much deeper reduction of the :minimal policy-composition bug, was closed by the stale-PR bot after 14 days with no maintainer review — not on merit. If that diagnosis is correct, the underlying policy defect (native runtime permissions being dropped whenever :root = read subsumes :minimal) is still present regardless of whether the __CF_USER_TEXT_ENCODING patch masks the symptom. That seems worth a look before this issue is closed.

Given the above, this issue is probably closeable on the original symptom, but we'd suggest confirming #24956's policy finding separately rather than letting it lapse with the bot closure. Happy to re-run our harness against any candidate build or a specific config if that's useful.