You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Markdown preview tab becomes unresponsive after Codex edits the file #33160
What version of the Codex App are you using (From “About Codex” dialog)?
26.707.72221
What subscription do you have?
Pro
What platform is your computer?
Darwin 25.5.0 arm64 arm
What issue are you seeing?
When a Markdown file is open in rendered/rich-text preview and Codex edits the file, that preview tab becomes unresponsive. Clicking the tab's close button does nothing. The tab remains stuck until I switch to a different Codex task and then switch back, after which the tab can be closed normally. The rest of the app remains responsive enough to switch tasks.
What steps can reproduce the bug?
Open a Markdown file in the Codex Desktop file viewer.
Switch the file to rendered/rich-text preview.
Ask Codex in the current task to edit that Markdown file.
After Codex applies the edit, click the preview tab's close button.
Observe that nothing happens and the tab cannot be closed.
Switch to a different Codex task, then switch back to the original task.
Click the tab's close button again; it now closes normally.
What is the expected behavior?
The Markdown preview tab's controls should remain responsive after Codex edits the underlying file. Clicking the close button should immediately close the tab without requiring a task switch.
Additional information
Workaround: switch to a different Codex task and then back to refresh the tab state.
This is distinct from #32571: the problem is not the preview switching to source/diff mode or losing scroll position. The tab's close action itself stops responding after the edit.
I can reproduce this on the Windows desktop app, and the production bundle plus logs point to a stale onBeforeClose guard rather than a missed pointer event.
Environment
Microsoft Store ChatGPT/Codex app: 26.715.8383.0
Embedded frontend: 26.715.61943
Windows 11 x64
Native local Windows host (not WSL or VMOS)
A generated/local Markdown file opened in the right-side file viewer
Evidence
The desktop breadcrumb records the actual click on the Markdown tab's close button, including the button aria-label. The click reaches the renderer.
The generic tab controller correctly supports closing index 0 and the final remaining tab: after removing the tab, an empty tab array closes the panel. The close is blocked before that reducer path.
In the shipped review-file-source-tab-CDePGYBR.js, the file editor lifecycle represented by MF effectively does this when the file is dirty:
If saveRef.current was null when the guard was installed, optional chaining does nothing but the guard still returns false forever.
If saveUntilClean() resolves false or rejects (load/write/conflict/read-only/path failure), the guard is not removed and there is no retry/discard path.
Editor cleanup unregisters the save callback but does not remove an already installed guard.
The JF open/reopen path unconditionally carries existing?.onBeforeClose into the new descriptor, so a guard from an old editor lifecycle can survive reopening.
In this reproduction, the same file open also hit the Windows path-normalization error tracked in #32474: a native path became /C:/..., and fs/watch failed with AbsolutePathBuf deserialized without a base path. That failure can make the save/load path return false and expose the stale guard.
After the failed close, the panel remained mounted. The log recorded 73 additional ResizeObserver loop completed with undelivered notifications messages over the next several minutes, along with high renderer CPU/memory churn (working set peaked around 1.59 GB). Chinese IME input became effectively unresponsive while the renderer was saturated. This confirms severe layout/render churn, though it is not enough by itself to prove a monotonic JS heap leak.
Suggested fix
Read saveRef.current when the close guard runs, not when dirty state installs it.
On missing save callback or load error, remove the guard and provide an explicit close path.
On save false/rejection, show Retry / Discard and close / Cancel; never leave a no-exit false guard.
Remove an owned guard on onSaveChange(null) and editor cleanup.
Track guard identity plus an editor/save epoch so an old cleanup or Promise cannot clear/close a reopened tab.
Deduplicate concurrent close attempts.
Do not inherit onBeforeClose across reset, path/host change, or a new editor lifecycle.
Disconnect the DetailPanel's observers and cancel any pending RAF during unmount.
No raw logs are attached because they contain local workspace and task metadata. I can provide targeted sanitized excerpts if maintainers need them.
Activity
Oct-2300 commentedon Jul 21, 2026
I can reproduce this on the Windows desktop app, and the production bundle plus logs point to a stale
onBeforeCloseguard rather than a missed pointer event.Environment
26.715.8383.026.715.61943Evidence
review-file-source-tab-CDePGYBR.js, the file editor lifecycle represented byMFeffectively does this when the file is dirty:This creates permanent blocking states:
saveRef.currentwas null when the guard was installed, optional chaining does nothing but the guard still returnsfalseforever.saveUntilClean()resolvesfalseor rejects (load/write/conflict/read-only/path failure), the guard is not removed and there is no retry/discard path.JFopen/reopen path unconditionally carriesexisting?.onBeforeCloseinto the new descriptor, so a guard from an old editor lifecycle can survive reopening.In this reproduction, the same file open also hit the Windows path-normalization error tracked in #32474: a native path became
/C:/..., andfs/watchfailed withAbsolutePathBuf deserialized without a base path. That failure can make the save/load path return false and expose the stale guard.After the failed close, the panel remained mounted. The log recorded 73 additional
ResizeObserver loop completed with undelivered notificationsmessages over the next several minutes, along with high renderer CPU/memory churn (working set peaked around 1.59 GB). Chinese IME input became effectively unresponsive while the renderer was saturated. This confirms severe layout/render churn, though it is not enough by itself to prove a monotonic JS heap leak.Suggested fix
saveRef.currentwhen the close guard runs, not when dirty state installs it.falseguard.onSaveChange(null)and editor cleanup.onBeforeCloseacross reset, path/host change, or a new editor lifecycle.No raw logs are attached because they contain local workspace and task metadata. I can provide targeted sanitized excerpts if maintainers need them.