[macOS] Overlapping Appshots leave a full-screen transition overlay stuck because cancellation is not propagated

Open 💬 1 comment Opened Jul 17, 2026 by ksmkzs

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

ChatGPT/Codex Desktop 26.715.21425 (CFBundleVersion 5488)

Computer Use helper:

CFBundleIdentifier: com.openai.sky.CUAService
CFBundleShortVersionString: 26.715.1000451
CFBundleVersion: 1000451

Distribution hashes:

app.asar:
5db4c67090c0521fa717e83e46cb0a6175cb6c16fb89064223753bdf05cff0aa

SkyComputerUseService:
44320516c4c400fb5459b203498c78e4af318b0096464f16c4445a47f2b8b8f4

What subscription do you have?

ChatGPT Pro

What platform is your computer?

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

What issue are you seeing?

If a second Appshot is started while an earlier Appshot is still pending, the later capture can complete successfully while the first capture's full-screen transition overlay remains above every application.

The stuck window is a native layer-25, full-display window whose class is:

Appshot.AppshotCaptureTransitionOverlayWindow

It displays the captured application image above all windows. The keyboard and underlying applications continue to run, but the overlay obscures the desktop until SkyComputerUseService is terminated or the native capture eventually unwinds.

This is not simply a failure to attach multiple completed images. The trigger is overlapping captures with distinct request IDs when the older request has emitted a screenshot but has not emitted axText or completed.

Observed request timeline

The following timestamps are UTC from ~/Library/Logs/com.openai.codex:

21:02:08.324  Mail capture created
               requestId=89221d90-ebfe-4885-bee7-c340dce41a37

21:02:09.017  Mail update: metadata
21:02:09.218  Mail update: screenshot
               No axText or completed update followed.

21:02:14.112  Safari capture created
               requestId=d0a99d24-4abc-45bd-81d7-8db5df888363

21:02:14.732  Safari update: metadata
21:02:14.764  Safari update: screenshot
21:02:14.860  Safari update: axText
21:02:15.190  Safari update: completed / status=success

The Mail transition overlay remained after Safari completed. After manually terminating the exact Computer Use service process, the Mail update watcher returned:

AESendMessage failed with -600

and the app finally settled the Mail request as discarded after 70.641 seconds.

A previous occurrence reached the app's 120-second timeout:

Timed out waiting for Codex Computer Use capture
elapsedMs=120835
hadAxText=false
hadScreenshot=true
status=discarded

but the native overlay remained visible well beyond the JavaScript timeout.

Installed-build implementation findings

The desktop implementation does not appear to be present in the public repository, so these locations refer to the installed distribution. The ASAR does not include its referenced source maps.

In app.asar/.vite/build/main-hw0RxS4P.js, raw line 366:

  • The pending-capture collection is FO = new Map() at byte offset 511678.
  • The capture-start handler VO() begins at byte offset 511839.
  • It rejects only FO.has(requestId), meaning duplicate requests with the same ID.
  • It does not reject a new request when another request ID is already pending and does not cancel/supersede the older request.
  • UO() at byte offset 513842 deletes the map entry, clears the timer, calls AbortController.abort(), and unsubscribes.
  • GO() at byte offset 514107 implements the 120-second timeout, but the cleanup does not invoke a native capture/transition cancellation operation.

In app.asar/.vite/build/worker.js:

  • The Computer Use capture worker begins near raw line 182, byte offset 1342319.
  • Its cancellation handler at byte offset 1343701 is exactly:
handleCancel() {}
  • The native bridge at raw line 206 exposes only:
ComputerUseIPCAppStartCaptureRequest
ComputerUseIPCAppNextCaptureUpdateRequest

No capture-cancel Apple Event request is present.

The native SkyComputerUseService binary does contain:

ComputerUse.AppshotCaptureStore.captures
Appshot.AppshotCaptureTransition.start()
Appshot.AppshotCaptureTransition.complete()
Appshot.AppshotCaptureTransition.cancel()
Appshot.AppshotCaptureTransitionOverlayWindow

AppshotCaptureTransition.cancel() is present at VM address 0x100ca5138 in this binary. Its implementation iterates the overlay windows and closes/removes them, but there is no ComputerUseIPCAppCancelCaptureRequest path from Electron to reach it.

During a stuck capture, a process sample showed the capture work blocked in synchronous Accessibility calls including:

AXUIElementCopyAttributeValue
AXUIElementCopyAttributeNames
AXUIElementCopyMultipleAttributeValues

The service imports those AX copy APIs but does not import/use AXUIElementSetMessagingTimeout.

Taken together, the failure path appears to be:

  1. The first capture creates and starts a native transition overlay.
  2. AX extraction stalls after the screenshot update.
  3. A second request ID is accepted and completes independently.
  4. Completing the second transition does not cancel the first transition.
  5. JavaScript abort/timeout disposes listeners and workers, but handleCancel() is empty and no native cancel request exists.
  6. The first native transition therefore retains its full-screen overlay.

What steps can reproduce the bug?

  1. Open Codex Desktop on macOS.
  2. Bring Mail to the foreground.
  3. Trigger an Appshot using the Double-Command shortcut.
  4. Before the first capture reaches axText / completed, switch to Safari.
  5. Trigger another Appshot.
  6. Observe that the Safari Appshot completes and is attached.
  7. Observe that the earlier full-screen Appshot transition remains above every application.
  8. Terminating only SkyComputerUseService clears the overlay and causes the pending update poll to fail with Apple Event error -600.

The timing depends on the first target's AX traversal stalling, but the same overlapping request shape has now been observed more than once.

What is the expected behavior?

Appshot capture should either be single-flight or explicitly supersede/cancel the previous capture.

Regardless of whether screenshot capture, AX extraction, update polling, or attachment fails:

  • no full-screen transition overlay should survive the request;
  • a later Appshot should not leave an older transition active;
  • the 120-second timeout should cancel the corresponding native capture, not only discard JavaScript state.

Additional information

Potential fix points:

  1. Add a single-flight guard in the main-process capture manager, or explicitly cancel all prior pending request IDs before accepting a new one.
  2. Implement the Computer Use worker's handleCancel(requestId).
  3. Add a native cancel Apple Event/IPC request that removes the request from AppshotCaptureStore and calls AppshotCaptureTransition.cancel().
  4. Put transition completion/cancellation in a guaranteed cleanup path so every error and cancellation closes the overlay.
  5. Bound AX traversal with AXUIElementSetMessagingTimeout, task cancellation, or a screenshot-only fallback when AX text cannot be collected.
  6. Preserve the native/worker failureReason; in this reproduction the final renderer log reported failureReason=undefined even though the worker emitted update_poll_failed.

I can provide additional redacted logs or a controlled process sample if needed.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗