Attach <App> (computer-use / Appshot capture) permanently freezes the session when the target is a backgrounded Electron app (e.g. Feishu/Lark)

Open 💬 0 comments Opened Jun 1, 2026 by ginping

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

26.527.31326 (build 3390)

What subscription do you have?

ChatGPT Pro

What platform is your computer?

Darwin 25.5.0 arm64 arm (macOS 26.5, build 25F71, Apple Silicon)

What issue are you seeing?

Clicking the dynamic Attach <App> item in the composer "+" menu (the computer-use / "Appshot" capture) hangs forever and freezes the entire session when the target is a non-foreground Electron app such as Feishu/Lark (com.electron.lark). There is no error toast and no timeout — the renderer becomes unresponsive and the app must be force-quit. The same capture path works fine for browsers (Chrome/Safari), which appear to be the well-tested case.

Relevant lines from ~/Library/Logs/com.openai.codex/.../codex-desktop-…log (PII redacted):

info [electron-message-handler] Appshot capture request created bundleIdentifier=com.electron.lark name=Feishu source=add_context_menu requestId=de935b9b-… info [electron-message-handler] Appshot capture start request sent bundleIdentifier=com.electron.lark name=Feishu requestId=de935b9b-… info [computer-use-capture-worker] Computer Use capture worker received start requestId=de935b9b-…

The matching Appshot capture start request finished line is never emitted. The session made no further progress and was force-quit ~4 min later (CrashReporter recorded a ForceQuitDate, i.e. an unresponsive-app kill, not a code crash).

What steps can reproduce the bug?

There is no code snippet — it is a UI action:

  1. Run an Electron app other than a browser in the background (Feishu/Lark, Clash Verge, Slack, Discord, VS Code…), so it is not the frontmost window and is partly/fully occluded by the Codex window.
  2. In Codex Desktop, open a session and click the "+" (attach) menu.
  3. Click the dynamic Attach <that app> entry (in my case Attach Feishu).
  4. The capture never completes → the session UI freezes (unresponsive), no toast, no recovery → force-quit required.

Reproduced with Feishu/Lark. Suspected for any non-foreground / occluded Electron window. The menu's offered target varies with whatever app is currently foreground (I've also seen Chrome and Clash offered).

  • Capture requestId: de935b9b-a6be-4b10-af00-6041552b6f0d
  • Token/context-window usage: N/A (failure is in the native capture path, before any model call)

What is the expected behavior?

  • The capture must have an end-to-end timeout + cancellation; on timeout, fail gracefully via the existing Unable to attach appshot toast. It must never block the session's interaction path.
  • Capturing a backgrounded/occluded or Electron-multi-process window should succeed (or fail cleanly), not hang.

Additional information

Likely root cause (from inspecting the shipped binaries + my logs):

The capture is performed by a separate ScreenCaptureKit child (Codex.app/Contents/Resources/codex_chronicle, Rust + a Swift ScreenCaptureKitBridge, screencapturekit-1.5.4 crate) using SCScreenshotManager.captureImageInRect:completionHandler:. The target window is selected by a privacy filter keyed on app_bundle_identifier + window_id (src/screen/privacy_filter.rs). On the JS side the composer does await O('computer-use-start-capture', {...}) inside a try/catch.

For an Electron target, the SCScreenshotManager completion handler is apparently never invoked, so the future/promise behind that await never settles. Because this interactive path has no end-to-end timeout, the whole renderer hangs. Contributing factors (all Electron-specific):

  1. Window-ownership mismatch — Electron's on-screen surface is rendered by the app's GPU/helper child process, not the main bundle process the menu identified. Building an SCContentFilter from bundle_id + window_id can resolve to a context the capture can't read → matches the binary's error strings No matching application context / Application connection invalid / Application connection interrupted.
  2. Occlusion + background throttling — the target was backgrounded and occluded by Codex; SCK can fail to call the completion handler for occluded/minimized/off-Space windows, and Electron's default backgroundThrottling stops hidden windows from rendering, so no frame is ever produced.
  3. No timeout on this path — codex_chronicle only has deadlines for failed to start ScreenCaptureKit child timeout and screen capture display enumeration timed out after …, not for the per-window capture completion.

The hang is silent rather than User declined screen recording, so Screen Recording permission was already granted — the stall is in frame delivery, not the TCC gate. Note that the binary special-cases browsers heavily (com.google.Chrome, .beta/.canary/.dev, SafariTechnologyPreview, Incognito/Private + Google Meet detection, BrowserWindowObservation), suggesting the generic "attach an arbitrary Electron app" path is under-tested.

Suggested fixes: wrap the computer-use-start-capture await (and the underlying SCScreenshotManager completion) in a timeout + AbortSignal → route to the existing failure toast; add a hard per-capture deadline in the SCK child; resolve the on-screen window by window-server window_id rather than assuming the main app pid owns the surface; for backgrounded targets capture the display region instead of a throttled hidden window.

Secondary issue — app won't relaunch after force-quitting an in-flight capture. After force-quit, ~/Library/Application Support/Codex/SingletonLock was left as a stale symlink (<host>-<dead-pid>), SingletonSocket/SingletonCookie remained, and orphaned codex app-server + node_repl processes survived. On relaunch the main process spawned but never reached app code (no new log written; stuck pre-main, ~96 KB; vmmap: "Process exists but has not started -- it is launched-suspended"). Killing only the GUI process and relaunching did not help. Fixed by killing all /Applications/Codex.app/... processes (main + codex app-server + node_repl) and removing SingletonLock/SingletonSocket/SingletonCookie, then relaunching. Suggest cleaning up the singleton lock + child processes robustly on abnormal exit / next launch.

View original on GitHub ↗