[Windows][Desktop 26.803.5235.0] Git review cancellation spams Electron "Error: write EOF"; disable toggle is hidden
What version of the Codex App are you using?
26.803.5235.0 (Microsoft Store/MSIX)
- Bundled Chromium/Electron annotation: 151.0.7922.76
- Codex CLI doctor: 0.147.0-alpha.6.5, windows-x86_64
Platform
Windows 11 Pro 10.0.26100 x64
Issue
Codex Desktop repeatedly opens a native Electron modal:
A JavaScript error occurred in the main process
Uncaught Exception:
Error: write EOF
at WriteWrap.onWriteComplete [as oncomplete]
(node:internal/stream_base_commons:87:19)
The main app and app-server remain alive, but modal dialogs recur while Git-based Review live queries are repeatedly canceled and retried in a large local repository.
Reproduction
- Open a large/dirty local Git repository in Codex Desktop.
- Keep a local task running while the Review panel/background review-model queries refresh.
- A background
git status ... --untracked-files=nomay hit the 60-second timeout. - The Git watcher restarts and
review-summary/branch-diff-statscommands enter a cancel/retry loop. - Electron main-process
write EOFdialogs begin recurring.
Correlated log evidence
At one reproduction:
- 19:18:41.895Z: background
git statustimed out after 60012 ms - 19:19:10.068Z:
[git-repo-watcher] Starting git repo watcher - 19:19:11 local capture: Electron
write EOFmodal - follow-on review commands repeatedly canceled; some returned about 741376 bytes stdout and 13-133 KiB stderr
Git itself is not generally hung: the same status command later completed in about 1.0s and fsmonitor reported healthy. The failure appears to be in Windows child-process cancellation/pipe handling plus live-query retry behavior.
Hidden workaround regression
The installed app bundle defines:
- key:
git-review-mode - values:
full/last-turn-only - UI label:
Disable Git-Based Review - description: it disables Unstaged/Staged/Branch to avoid Git operations
Settings search finds Disable Git-Based Review, but Settings → Git does not render the toggle. The settings component appears feature-gated out.
Adding this to config.toml is accepted by strict config validation:
[desktop]
git-review-mode = "last-turn-only"
However, the running desktop process does not hot-reload it; a restart is required.
Expected behavior
- Canceling or timing out Git children should handle EOF/EPIPE without an uncaught Electron exception/modal.
- Live Git queries should back off instead of entering a cancel/retry loop.
- Disable Git-Based Review should be visible if it is indexed by Settings search.
git-review-modechanges should hot-reload, or the UI should state that a restart is required.
Privacy
Local username, repository path/content, and project media are omitted. Sanitized log excerpts and screenshots are available if needed.
4 Comments
Confirmed recurrence after a full process restart with the workaround loaded.
``
toml
``[desktop]
git-review-mode = "last-turn-only"
Despite that setting, the new session continued issuing
source=review_model requestKind=review-summarycommands. The post-restart log shows:git diff ... --find-renames --raw --no-abbrev --numstat -zcanceled/retried about once per second.git diffandgit status --renames --porcelain=v1 -z --untracked-files=nocalls.git statuscompleted withdurationMs=60010,failureReason=timed_out,timedOut=true.Error: write EOFrecurred afterward.Therefore
last-turn-onlyis not an effective workaround in Desktop 26.803.5235.0. It may reduce activity initially, but it does not stop Review-model Git operations or prevent the cancellation/pipe crash.Current requested fixes remain:
Still reproducing on a newer build than the one in the report, with the same modal and the same stack. Adding a detail I haven't seen named in this thread (or in #38360 / #38202 / #35985): a specific stdin-fed git child that gets aborted mid-write.
Environment
| | |
|---|---|
| Codex Desktop |
OpenAI.Codex_26.803.10989.0_x64__2p2nqsd0c76g0(MSIX), release26.803.81509|| Bundled Chromium/Electron |
151.0.7922.76(same annotation as this report) || OS | Windows 11 Pro
10.0.26200x64 || Workspace | local git repo with ~64,000 untracked files |
The cancel/retry loop is confirmed here
One main-process log for a single day records, across
git.command.completeentries: 11×failureReason=canceled, 3×timed_out, 2×nonzero_exit— includinggit statusat 60014 ms andgit ls-files --others --exclude-standardat 60001 ms, bothrequestKind=status-summary. That matches step 3–4 of the repro in the original report.The candidate writer:
git hash-object --stdin-pathsTwo entries stand out, because this is the only git invocation in the flow that receives its input over stdin (paths are streamed into the child, one per line):
stdoutBytes=12915together withaborted=truemeans git had already streamed ~13 KB of hashes back when the cancellation landed — i.e. the parent was still feeding paths into the child's stdin at kill time.Note the
requestKind=review-summary source=local_conversation_git_actionstag: samereview-summarypath this report calls out.Why this fits
write EOFspecificallyOn Windows, writing to a pipe whose read end has gone away yields
ERROR_BROKEN_PIPE, which libuv maps toUV_EOF— so Node surfaces it aswrite EOF, notEPIPE. A socket peer-reset would normally readEPIPE/ECONNRESETinstead (as in thebrowser-usenative-pipe path in #38360). A killed child's stdin is therefore a much better fit for the exact string in this modal, plus itsWriteWrap.onWriteCompleteframe.Caveat — this is correlation, not a captured trace
The app's own logger contains no
EOF/EPIPE/ uncaught-exception entry anywhere in its log tree. The exception goes straight to Electron's defaultuncaughtExceptionhandler →dialog.showErrorBox, so there is no logged timestamp to line up against the modal. I'm offeringhash-object --stdin-pathsas a lead because it is the one place in this flow where the parent holds a writable handle to a child it also cancels — not as a proven trace.Suggested fix / check
Wherever
hash-object --stdin-pathsis driven, the child'sstdinshould get an'error'listener before the cancellation path can kill the process, andwrite()calls should be guarded ondestroyed/writableEnded. Worth auditing every other stdin-fed child spawned by the git layer the same way, since any of them can lose its reader mid-write during a cancel.One divergence from the reports in this thread
Contrary to "the modal blocks the app" (reported here and in #38360), on my install the main process keeps running with the dialog open — it is still logging normally while the un-dismissed modal sits on screen. So the blocking behaviour appears to vary, which may be worth accounting for when reproducing.
I can confirm the hidden Settings-search mismatch independently on macOS.
Environment
26.810.52044(build6662)26.6.1(25G76)Reproduction
turn.This reproduces the hidden/feature-gated settings UI problem described in this issue, independently of the Windows
write EOFfailure. Search should not index a control that is unavailable to the current account/build, or the Git page should expose the control and explain its rollout status.I also added the undocumented setting below locally:
The config parses successfully, but the desktop app requires a full restart before its UI behavior can be verified. I can follow up after testing. A screenshot of the Settings search mismatch is available and contains no private repository data.
Follow-up after testing the undocumented setting on macOS with a full desktop-app restart:
Environment:
26.810.52044(build6662)26.6.1(25G76)Observed behavior:
Ctrl+Shift+Gis still required.Uncommitted,Unstaged,Staged,Committed, andBranch.So, in this macOS build, the key behaves like a persistent/default scope preference rather than a literal “Last Turn only” UI lock. This test does not establish whether the setting suppresses background Review-model Git operations.
The remaining supported-UX request is tracked in #38875: expose the default scope as a normal preference and optionally open/restore the Review pane automatically.