[Desktop/macOS] Renderer freezes after referencing large local Codex chats while backend tasks continue
Summary
Codex Desktop on macOS becomes completely non-interactive after using the @ mention interface to reference large existing local Codex chats.
When this happens, mouse and keyboard input stop working, but per-task spinners remain animated and background tasks continue running. Tasks can complete successfully while the window remains frozen. Force-quitting and reopening temporarily restores access, but reopening the reference-heavy task can freeze the renderer again.
This appears to be a desktop renderer responsiveness failure rather than a model, network, app-server, database, or filesystem-search failure.
Environment
- Codex Desktop:
26.715.61943 - Desktop build:
5628 - Bundled Codex backend:
0.145.0-alpha.27 - Chromium/Electron framework:
150.0.7871.124 - OS: macOS
26.5.1, arm64
Steps to reproduce
- Create or identify two long local Codex chats with substantial histories.
- Start a new Codex task.
- Type
@in the composer and select both existing chats as references. - Submit a short request.
- Optionally leave other tasks streaming in the background.
- Navigate away from the new task and then reopen or resume it.
A related UI stall has also been observed while searching for files or chats through the @ menu while other tasks are streaming.
Actual behavior
- The desktop renderer stops servicing user input.
- The native application process and bundled app-server remain alive.
- Background task output continues to be generated for the connected desktop client.
- Turn-completion events are generated but are not reflected by the frozen window.
- Reopening the affected task can reproduce the freeze.
- No renderer crash dialog, fatal error, panic, or out-of-memory termination is produced.
Expected behavior
- Referencing a large chat must not block the desktop renderer.
- Large references should be bounded, summarized, truncated, or loaded lazily.
- The
@result menu should remain responsive while its result sources update. - Background streaming events should not starve input handling.
- Completed or interrupted turns should not remain marked as streaming.
- If a reference exceeds a supported limit, the app should reject it recoverably rather than persisting a task that freezes when reopened.
Sanitized investigation results
Reference expansion
The reproduction referenced two local Codex chats containing 325 and 118 conversation items, or 443 embedded items in total.
The generated context contained:
- 456,237 characters of serialized reference data
- 456,662 characters in the complete generated user-context record
- 312 characters in the actual user request
The reference data was represented as one extremely long serialized line. It was persisted in two event representations, accounting for approximately 0.92 MB of a 1.25 MB task record.
Across the inspected local session corpus, reference payloads frequently reached tens or hundreds of thousands of characters. This 456k-character payload was the largest observed.
Packaged reference serializer
Inspection of the packaged renderer shows the referenced-chat collection being appended using the equivalent of JSON.stringify(threadReferences). There is no character, byte, or item budget at that serialization point. The captured payload demonstrates that at least 443 conversation items can reach it without truncation.
There may be limits elsewhere in the system, but they did not prevent this reproduction.
Backend loading and state
For the affected task:
thread/readcompleted in approximately 14 ms.thread/resumecompleted in approximately 195 ms.- The backend described the latest turn as interrupted while renderer-side state still marked the task as streaming.
This suggests the freeze is not caused by slow session storage or thread loading. The interrupted/streaming state mismatch may also explain persistent spinner state.
Work continued after the renderer stalled
After the UI stopped responding, the same bundled backend process produced approximately:
- 2,000 additional diagnostic records
- 348 agent-text delta events
- 246 command-output delta events
- Peaks of 58 agent-text deltas per second
Events were still directed toward one connected desktop client. The active turn later completed successfully, and no new deltas followed, but the window remained unusable.
@ menu behavior
A non-empty @ query can concurrently update file, existing-chat, plugin, skill, application, and agent results. File and chat searches are debounced by approximately 100 ms, and chat search can return up to 50 results before the sections are merged.
The result menu preserves its highlighted item while sections change and remeasures layout using ResizeObserver plus animation frames. The observer watches both the menu element and the document root.
Captured fuzzy-file-search requests completed in 0-87 ms. This makes filesystem search itself an unlikely cause of file-related stalls; result reconciliation or layout is a more likely bottleneck.
Renderer layout churn
Two desktop sessions emitted repeated ResizeObserver loop completed with undelivered notifications warnings:
- 841 occurrences in one session
- 178 occurrences in the following session
The warnings arrived in bursts around chat navigation, streaming updates, and task switching. The packaged app excludes this warning from Sentry, so it is treated here as evidence of layout churn rather than proof of the root cause.
Logging and disk-write pressure
Additional generic diagnostics:
- The local diagnostic SQLite log database was approximately 405 MB with about 205,000 records.
- A macOS resource report recorded approximately 2.15 GB written by the bundled backend over 4,745 seconds; SQLite writes appeared in the heaviest sampled stack.
- A separate desktop-process report recorded approximately 2.15 GB written over 3,683 seconds and a maximum footprint of approximately 515 MB.
This may not be the primary renderer lock, but high-volume trace logging and SQLite writes appear to reduce available performance headroom.
Checks that passed
The following were verified and do not appear to explain the freeze:
- OpenAI endpoint reachability
- Responses WebSocket handshake
- Authentication configuration
- Main state-database integrity
- Diagnostic log-database integrity
- Session-rollout and state-database parity
- Saved-thread inventory consistency
- Auxiliary database integrity using immutable read-only checks
- Filesystem fuzzy-search response time
There was no evidence of a renderer crash, render-process-gone, fatal error, panic, out-of-memory termination, model/API outage, or corrupted task record.
Suspected cause
The strongest hypothesis is renderer-main-thread starvation caused by a combination of:
- Unbounded serialization of complete referenced-chat histories
- Rehydration and normalization of the resulting large user-context record
- Concurrent streaming deltas from background tasks
- Dynamic
@result-section reconciliation - Repeated layout measurement through
ResizeObserver - High-volume diagnostic logging and SQLite writes
Without a live renderer stack sample, it is not possible to determine whether the hottest operation is JSON processing, React reconciliation, Markdown or mention parsing, or layout callbacks.
Suggested fixes
- Add an explicit character, token, byte, or item budget for referenced chats.
- Avoid serializing a complete chat history into one unbounded JSON string.
- Summarize or compact large referenced chats before adding them to a new task.
- Process or normalize reference context outside the renderer thread.
- Ensure hidden model context is removed before Markdown or mention parsing.
- Add backpressure or stronger coalescing for renderer streaming events.
- Virtualize and cap
@menu result sections. - Avoid observing the document root when only menu placement needs updating.
- Reconcile interrupted and completed turns so they cannot remain marked as streaming.
- Bound or rotate diagnostic SQLite storage and reduce trace-event write volume.
- Add performance telemetry for reference size, renderer task duration, event-queue depth, and menu layout cycles.
Workarounds
- Produce a concise handoff document from the source chat and reference that file instead of the complete chat.
- Type an explicit relative file path instead of using the
@picker. - Avoid reopening a task containing very large chat references.
- Reduce the number of simultaneous streaming tasks.
- Force-quit and reopen the app after confirming background turns have completed.
Related issue
#32342 reports a closely related poisoned-task failure on Windows involving a server-backed ChatGPT conversation and a long prompt. This report is separate because the reproduction is on macOS, uses two large local Codex-chat references, and occurs with a short 312-character request. The renderer/backend split and unbounded reference-payload measurements are also independently captured here.
Privacy
Raw transcripts, desktop logs, local paths, identifiers, and attachments are intentionally not included because they may contain confidential workspace information.
This report contains aggregate measurements and generic application diagnostics only. It contains no project names, repository names, prompts, chat titles, source paths, thread or conversation identifiers, ticket identifiers, account identifiers, or tool output. Additional sanitized measurements can be provided if maintainers specify the fields needed.
1 Comment
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action