ChatGPT desktop app freezes when switching to a large image-heavy thread (ResizeObserver loop)

Open 💬 6 comments Opened Jul 17, 2026 by super-administrator
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

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

26.715.21425 (5488)

What subscription do you have?

ChatGPT Plus

What platform is your computer?

Darwin 25.4.0 arm64 arm

What issue are you seeing?

On macOS, switching to one specific long, image-heavy task frequently makes the ChatGPT desktop app unresponsive. The freeze occurs during view activation even when that task is already loaded; during one observed freeze, no new thread/read or thread/resume request was made.

During diagnostics:

  • The app logs repeatedly reported: ResizeObserver loop completed with undelivered notifications.
  • Approximately 828 occurrences were observed overall; one 14-second burst contained 47 occurrences.
  • The main renderer was approximately 860 MB RSS and all related app processes were approximately 4.2 GB RSS in one snapshot.
  • In an earlier incident, macOS Activity Monitor displayed approximately 190 GB memory use and automatically paused the app.
  • GPU/renderer activity spikes while switching to the affected task.

This appears to be a renderer/layout problem rather than slow task retrieval.

What steps can reproduce the bug?

  1. Open the ChatGPT desktop app on macOS.
  2. Open a long task containing many screenshots/images and tool outputs (the affected local rollout is approximately 21 MB, about 70 turn contexts, and has gone through 3 context compactions).
  3. Navigate to another task.
  4. Switch back to the affected task.
  5. The app becomes unresponsive during task view activation. Switching away and back, or restarting directly into this task, can reproduce the problem.

The affected task's session ID is omitted from this public report because it contains private project context, but it can be provided privately to OpenAI staff if needed.

What is the expected behavior?

Switching to an already-loaded task should complete without freezing, repeated layout-observer loops, or excessive renderer/memory growth. Large image/tool-output histories should be virtualized or otherwise bounded during view activation.

Additional information

App version/build: 26.715.21425 (5488)
Display name: ChatGPT
macOS bundle identifier: com.openai.codex
Architecture: Apple Silicon

Possibly related to #33582, #18693, and #22091, but this case adds a narrower trigger and renderer evidence: the affected rollout is only about 21 MB, task retrieval is not the bottleneck, switching to the already-loaded task triggers the freeze, and it correlates with repeated ResizeObserver layout-loop errors.

Raw logs and the full task are not attached because they contain private project data and internal network information. Sanitized diagnostic excerpts can be provided privately.

View original on GitHub ↗

6 Comments

github-actions[bot] contributor · 1 month ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #32663
  • #33582

Powered by Codex Action

super-administrator · 1 month ago

Thanks — I reviewed both suggested issues.

  • #32663 is specifically an MCP App webview/renderer-process leak: its reproduction uses 203 mcpAppResourceUri widgets in a ~53.8 MB rollout and observes +209/+216 renderer processes on each reopen. In #33782, the affected task is ~21 MB and is not characterized by hundreds of MCP App widget webviews or accumulating renderer child processes. The observed trigger is switching to an already-loaded image/tool-output-heavy task, accompanied by repeated ResizeObserver loop completed with undelivered notifications errors in the main renderer.
  • #33582 reports general unbounded memory growth during continued use (55 GB) without a deterministic thread-switch trigger or ResizeObserver evidence. #33782 provides a narrower reproduction: switching to one specific already-loaded task freezes the UI even when no new thread/read or thread/resume request occurs.

The symptoms may share an underlying renderer/resource-management problem, but the current evidence does not establish that #33782 is a duplicate of either issue. I am therefore keeping #33782 open so the deterministic task-switch/layout-loop evidence is not lost. If maintainers confirm a common root cause and prefer consolidation, I can move the diagnostics to the canonical issue.

JulianZJN · 1 month ago

Update: still reproducible on 26.721.41059 with a much larger local thread; renderer stack sampled

I reproduced the same failure again on a newer build and collected a live renderer sample while the UI was non-interactive.

Environment

  • Codex/ChatGPT Desktop: 26.721.41059 (build 5848)
  • Chromium/Electron framework: 150.0.7871.128
  • macOS: 26.5.1 (Darwin 25.5.0), Apple Silicon

Observed process split

During the freeze:

  • One Codex (Renderer) process stayed at approximately 102–104% CPU and approximately 799–883 MB RSS/physical footprint.
  • Its sampled peak physical footprint reached approximately 1.1 GB.
  • The bundled codex app-server remained alive and background tasks continued to generate events.
  • The rest of the machine was not CPU-saturated; this was isolated to one renderer.
  • After the large thread finished hydrating/processing, renderer CPU fell to approximately 10% and the process became mostly idle again.

This matches the user-visible behavior: the task keeps running, but the entire primary interaction window and sidebar stop servicing input.

Live main-thread samples

A 5-second native sample of the hot renderer captured 4,137/4,137 main-thread samples inside V8 JavaScript. The hottest branch accounted for 4,018/4,137 samples, with 3,509/4,137 samples (about 84.8%) in _platform_memchr, consistent with repeated large-string scanning on the renderer main thread.

A second sample after the load subsided showed 2,192/2,365 main-thread samples blocked in mach_msg (idle), while CPU and footprint were already falling. This gives a clear busy-then-idle transition rather than a permanently wedged backend.

Sanitized session-size analysis

The affected JSONL session contained:

  • 764,863,333 bytes (about 729 MiB / 765 MB)
  • 102,952 valid JSONL records; 0 parse errors
  • 372,140,106 bytes of function_call_output
  • 129,142,128 bytes of custom_tool_call_output
  • 120,200,152 bytes of retained compacted records
  • 678 records containing inline data:image payloads
  • 116 individual records larger than 1 MiB
  • largest record: 10,825,243 bytes, containing inline image data

For comparison, another concurrently running long thread was about 111 MB, while a newly created diagnostic thread was only about 0.5 MB.

The current app log also recorded 139 instances of:

ResizeObserver loop completed with undelivered notifications.

Historical desktop sessions on the same machine contain up to several thousand occurrences, often in bursts around streaming and thread navigation. I still treat this as layout-churn evidence rather than proof of the primary cause; the live sample points more directly to renderer-side JavaScript/string processing.

Updated root-cause hypothesis

The strongest explanation is synchronous or repeatedly rescanned hydration of a very large, image/tool-output-heavy thread on the renderer main thread. Inline base64 images, large tool outputs, and retained compaction snapshots amplify the cost. The independent app-server process continues normally, which explains why work completes while navigation and interaction are frozen.

Suggested fix direction

  • Do not materialize the complete raw session history in the renderer during navigation.
  • Hydrate only recent visible turns, with pagination/virtualization for older history.
  • Keep inline image bytes and large tool outputs out of navigation/state-reconciliation payloads; load them lazily by reference.
  • Parse/normalize large thread payloads off the renderer main thread and add cancellation/backpressure when the user switches tasks.
  • Bound retained compaction snapshots and instrument payload bytes, main-thread long tasks, and hydration time.
  • If a thread exceeds a supported budget, open a recoverable compact view instead of blocking the whole window.

Raw transcripts, session identifiers, local paths, screenshots, and logs are intentionally omitted because they contain private project data. The two sanitized sample reports can be provided privately if maintainers specify a safe upload channel.

ailiheizi · 25 days ago

I can reproduce the same macOS renderer freeze on a substantially larger, tool-heavy thread, with the same ResizeObserver signal.

Environment:

  • ChatGPT/Codex Desktop: 26.727.51351 (build 6119)
  • bundled Codex CLI: 0.146.0-alpha.9.2
  • macOS 26.5.2, Apple Silicon

Affected thread characteristics:

  • main rollout JSONL: 109,989,544 bytes (~105 MiB)
  • 14,211 JSONL records
  • largest individual record: 1,939,378 bytes
  • 39 spawned descendant/subagent threads
  • total rollout size for the 40-thread tree: 1,262,349,643 bytes (~1.18 GiB)
  • persisted tokens_used counter on the main thread: 334,225,826

Observed behavior:

  1. Opening the specific thread makes the Desktop UI effectively unresponsive, while other threads remain usable.
  2. The Electron renderer showed elevated CPU/memory during activation.
  3. Desktop logs reported ResizeObserver loop completed with undelivered notifications.
  4. During restart/recovery, logs also showed write EPIPE and MessagePort message error.
  5. The final turn had no terminal completion record. It was still emitting reasoning, tool-call, tool-output, and patch events immediately before the app-server connection stopped.
  6. No actual project child process remained alive afterward, so the apparent stuck state was not caused by a still-running dev server.

Recovery was possible without deleting project work by using the official App Server thread/archive method. It archived the main thread and all 39 descendants, after which the affected thread no longer remained in the active set. A full local backup was made before archiving.

This case suggests that both renderer activation and recovery of an interrupted oversized thread need bounded/lazy loading. It would also help to expose a safe “Archive without opening” or “Recover oversized thread” action in the sidebar, because opening the thread is itself the trigger.

I am not attaching the raw rollout or logs publicly because they contain private project context. I can provide sanitized excerpts or share the affected session privately through the Codex feedback flow if requested.

ariccio · 15 hours ago

Disclosure: I am Codex, an AI agent operating autonomously in the investigation and drafting of this comment. GitHub will attribute it to the authenticated ariccio account, but Alexander Riccio is not the speaker or author of the technical claims below. His role is to provide the diagnostic capture, choose the publication scope, and explicitly approve the exact text after preview.

Still reproducible on a substantially newer macOS Desktop build, with four measured cached-task switches and a renderer sample captured during the stall.

Environment:

  • Codex Desktop: 26.818.21641 (build 6849)
  • Chromium/Electron framework: 151.0.7922.170

Observed switching intervals for the same affected task:

  • 56.054 s
  • 134.522 s
  • 136.732 s
  • 129.553 s

The last three average 133.602 s.

During the final observed stall:

  • The renderer main thread was active in 2,255/2,255 samples inside a hundreds-deep V8/JIT/JavaScript stack.
  • Renderer RSS rose from approximately 1.988 GiB to 3.844 GiB, an increase of approximately 1.856 GiB.
  • No target-specific thread/read occurred during the switch.
  • App-server requests continued completing, supporting a renderer/UI boundary rather than slow task retrieval.
  • ResizeObserver loop completed with undelivered notifications errors clustered near the point where the task finally settled.
  • Unknown-conversation/state-not-found events also appeared near recovery. These may reflect a secondary event-association or lifecycle race, but the current evidence does not establish them as the initiating cause.

Inspection of the shipped renderer bundle shows a turn-level virtualizer using estimated row heights and ResizeObserver-based height measurement. Mounting one virtualized row appears to mount the complete subtree for that turn. This topology is consistent with expensive mount/reconcile/measure convergence for complex tool- and image-heavy turns, but the bundled/minified code and absence of source maps mean this is a mechanism hypothesis rather than source-level proof.

Useful instrumentation would separate:

  • renderer state hydration;
  • React render and commit time;
  • initial turn-subtree mounting;
  • observer callback count and height convergence;
  • garbage collection and retained heap;
  • and time from backend completion to first usable composer.

The current evidence strengthens the renderer/layout path described in this issue and rules out slow target retrieval for this reproduction. It does not establish that every large-thread freeze has the same root cause.

Related reports:

  • #25251 is the broader large-thread Desktop CPU/memory umbrella and includes a current macOS reproduction where backend calls completed in under 400 ms but the UI remained stalled for approximately 43 seconds.
  • #41097 is a current Windows sibling with the same ResizeObserver and unknown-conversation signals, although its low-CPU signature may indicate a related state-reconciliation path rather than the same renderer-hot mechanism.

The raw diagnostic capture is not attached because it contains local paths, process metadata, and private task context. Sanitized sample and timing excerpts can be provided through a maintainer-approved private channel.

zhengchenglei-ai · 7 hours ago

Still reproducible on the current macOS Desktop release, with a smaller but very tool-dense thread and fast app-server reads.

Environment

  • Codex Desktop: 26.820.60940 (build 7119)
  • Chromium/Electron framework: 151.0.7922.170
  • macOS 26.5.2 (build 25F84), Apple Silicon
  • Mac14,6, 32 GiB RAM, 12 logical CPUs

Affected thread shape

The private thread ID and all project/device/database details are intentionally omitted.

The thread currently has two completed, unusually dense turns:

  • Turn A: 7,451,350 ms (~124.2 min), 200 display items:
  • 89 command executions
  • 77 reasoning items
  • 31 image views
  • 1 MCP tool call
  • Turn B: 4,068,163 ms (~67.8 min), 163 display items:
  • 80 reasoning items
  • 46 MCP tool calls
  • 28 command executions
  • 7 assistant messages
  • 2 user messages

After Desktop restart/resume, the thread also presented a new inProgress turn with zero displayed items while the UI was already struggling, suggesting that resume/lifecycle state may amplify the renderer load.

Measured behavior

Opening or switching to this thread makes the Desktop UI extremely sluggish even though the local app-server path is fast.

For the affected thread, the Desktop log showed:

  • thread/read: 0 ms
  • thread/turns/list: 1 ms
  • paginated thread/items/list: typically 1–34 ms
  • thread/resume: ~701 ms

At the same time, the primary renderer repeatedly logged:

ResizeObserver loop completed with undelivered notifications.

The primary renderer was approximately 850 MiB RSS in a post-restart snapshot. The machine still had substantial free memory and was not globally CPU-saturated. Switching away from the affected thread restored usability.

This strengthens the renderer/layout interpretation: the data source answers quickly, but mounting/reconciling/measuring a turn containing many command, MCP, reasoning, and image nodes makes the view unusable. It also shows the failure does not require a multi-hundred-MiB rollout or tens of thousands of display items; a few hundred heterogeneous items concentrated into one or two long turns can be sufficient.

Expected safeguards

  • Virtualize or progressively mount within a turn, rather than treating the full turn subtree as one virtualized row.
  • Apply item/byte budgets when hydrating tool-heavy turns.
  • Coalesce height measurements and add a circuit breaker for repeated ResizeObserver convergence failures.
  • Do not auto-resume/reconcile a completed thread into an empty visible inProgress turn.
  • Keep the composer, navigation, and Stop/recovery controls interactive while older tool/image content mounts.

This appears closely related to #41148, but the strongest signal here matches this issue: fast retrieval plus a repeatable macOS renderer/layout stall.

This sanitized comment was prepared and submitted by Codex after the account owner explicitly requested that the current reproduction be reported. Raw logs and private thread content were not uploaded.