openai / openai/codex

MCP App stays blank after side-panel opening until resize: possible lost spring completion visibility update

Open
#44,370 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

app bug mcp
Dominant language
Rust
Stars
125k
Forks
19.4k
PR merge metrics
PR metrics pending

Description

What version of the Codex App are you using (From “About Codex” dialog)?

26.901.51231 (build 8109), verified from the installed application's version metadata.

What platform is your computer?

macOS, Apple Silicon. uname -mprs: Darwin 25.6.0 arm64 arm.

What issue are you seeing?

An MCP App renders inline, but intermittently becomes entirely blank when it requests fullscreen in the right side panel. The entire app disappears, including its header. Dragging the conversation/panel splitter restores the content without reloading the app. Sending a chat message also restored it in one observation.

The request itself succeeds quickly. In a failing trace, requestDisplayMode returned after 23 ms, but the app document remained hidden and host-reported container dimensions remained 0 x 0 through the 5580 ms sample.

What steps can reproduce the bug?
  1. Open an inline MCP App in Codex Desktop with the right panel closed.
  2. From a button click, call app.requestDisplayMode({ mode: 'fullscreen' }).
  3. If the panel is blank, wait at least six seconds without resizing or sending a message.
  4. Drag the conversation/panel splitter slightly: the app content appears.
  5. As a control, first open a file in the right panel and let that panel fully open, then expand the same MCP App. In the confirmed control, it became visible after 25 ms and stayed visible through the 5002 ms sample, with unchanged app code and Codex version.

The failure is intermittent; a single successful expansion is not sufficient to rule it out.

Reproduced with @modelcontextprotocol/ext-apps 1.7.5, @modelcontextprotocol/sdk 1.30.0, and new App(appInfo, {}, { autoResize: true }). The page uses a 780 px inline body height and 100vh in fullscreen. Its click handler awaits the returned mode and updates its own display-mode attribute. No data loading is triggered by expansion.

A stripped control page containing only a header, text, the expand/collapse button, and diagnostic listeners also failed in native Codex. Workflow rendering, canvas libraries, business polling, and UI locking were removed. The SDK, App identity, height policy, autoResize, and diagnostics remained shared, so this control does not independently exclude those factors.

What is the expected behavior?

The app should become visible when the right panel finishes opening, without a manual resize or unrelated chat update.

Additional information
Native observations

Times are relative to the expand click. These are projections of app-internal diagnostic traces, not measurements of the outer native DOM.

Run Request response Observed visibility Host dimensions
Full app, failing 23 ms Still hidden at 5580 ms 0 x 0
Stripped control, failing 20 ms Still hidden at 5966 ms 0 x 0
Full app, right panel already open, user-confirmed 26 ms Visible at 25 ms; remained visible through 5002 ms Restored to 785 x 1038 at 29 ms

In the failing runs, the app's own body still had display: block, visibility: visible, and opacity: 1, with nonzero internal geometry. Its operation overlay was hidden and the workbench was not inert. No post-click resize or return-to-visible event arrived during the failing observation window.

Candidate cause from read-only inspection of the installed bundle

The relevant code in app-primary-6cd7b8b3f5e3.js and app-initial-cadb12d4a15e.js suggests a lost final visibility update:

  1. Right-panel opening uses a spring with duration 0.5 seconds and bounce 0.1.
  2. Panel width is derived by clamping raw progress to [0, 1].
  3. The shell publishes rightPanelLayoutTick when that derived width changes.
  4. The fullscreen frame's layout callback hides the frame unless raw progress is exactly 1.
  5. The raw spring overshoots 1 before settling. Width has already reached its clamped final value, so settling to exactly 1 produces no final width-change/layout notification.
  6. Without another layout event, the frame can remain hidden. A later resize reruns the visibility check and restores it.

Samples from the extracted installed spring, for a target width of 1117 px:

Time Raw progress Clamped width
375 ms 1.000613257460101 1117
499 ms 1.0009485905572695 1117
500 ms 1 1117

This mechanism reproduces in an isolated harness that retains width-derived layout notifications. It is consistent with the native observations, but live outer-container animation progress was not directly captured in native Codex.

Candidate patch

Subscribe raw animation progress to the existing requestAnimationFrame-coalesced layout callback, and unsubscribe in both cleanup branches. In the inspected bundle, ce2 is raw panel progress and o11 schedules the existing layout callback.

The diff below targets a formatted extraction of the installed bundle, for maintainer source mapping. app-primary.pretty.js is not a file in this public repository. This is not a patch to the CLI or app-server, and no installed application files were modified.

--- a/app-primary.pretty.js
+++ b/app-primary.pretty.js
@@ -28862,14 +28862,15 @@
         a11 = null, i11();
       });
     };
+    const stopVisibilitySync = ce2.on(`change`, o11);
     if (i11(), typeof ResizeObserver > `u`) return () => {
-      n11.disconnect(), a11 != null && window.cancelAnimationFrame(a11);
+      stopVisibilitySync(), n11.disconnect(), a11 != null && window.cancelAnimationFrame(a11);
     };
     let s11 = new ResizeObserver(i11);
     s11.observe(e11), s11.observe(wt2);
     let c11 = XE(e11, Oe2, o11, { ancestorResize: false, ancestorScroll: false, elementResize: false }), l11 = pe2.on(`change`, o11);
     return () => {
-      s11.disconnect(), c11(), n11.disconnect(), l11(), a11 != null && window.cancelAnimationFrame(a11);
+      stopVisibilitySync(), s11.disconnect(), c11(), n11.disconnect(), l11(), a11 != null && window.cancelAnimationFrame(a11);
     };
   }, [Oe2, Tt2, xt2, _e2, Ne2, ce2, pe2, Ae2, bt2, wt2]), (0, xW.useLayoutEffect)(() => (ve2.current = false, () => {
     ve2.current = true, M10.get(fW, u10)?.hostedInThreadScrollLayout !== true && ($U(M10, u10), cW(M10, u10, { isFullScreen: false }));
Validation and remaining work
  • 10 isolated callback tests passed, including the actual extracted spring and width-notification chain at 60, 90, and 120 Hz, a zero-bounce control, and subscription cleanup/coalescing checks.
  • A local browser fixture with real ResizeObserver and requestAnimationFrame reproduced the original frame staying hidden at progress 1; the candidate restored visibility. Both paths received the same 44 width-derived layout ticks.
  • The patch dry-run passed against the unchanged formatted extraction.
  • A patched native Codex build has not been run. The fix remains a candidate pending maintainer validation, including closed-panel and already-open-panel expansion, rapid collapse/reopen, and cleanup on unmount.

Related reports: #35786 and #44156 discuss MCP App disappearance at particular panel widths and transformed/covered containers. This report adds an opening-transition case with persistent document.visibilityState === 'hidden', host dimensions 0 x 0, and an independently reproduced spring/notification mechanism. Whether these reports share a cause has not been established.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by mapping the inspected app-primary-6cd7b8b3f5e3.js and app-initial-cadb12d4a15e.js logic to public source, then trace raw panel progress (ce2) and the existing layout callback (o11). Re-run the isolated callback checks and validate a patched native Codex build for closed-panel expansion, already-open-panel expansion, rapid collapse/reopen, and unmount cleanup. Done means the app becomes visible without resize or chat activity and existing cleanup remains intact.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
desktop, frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.