Windows Desktop 26.707.72221: invalid heartbeat target `thread` is accepted and retried every 4–5s, causing high CPU
[!IMPORTANT] Root-cause correction (2026-07-15): Subsequent investigation showed that/index.htmlwas incidental, not the source of the literalthreadvalue. A malformed heartbeat automation was created withtargetThreadId: "thread", and the automation API accepted and persisted it astarget_thread_id = "thread". Desktop then retriedthread/readandthread/resumeevery approximately 4–5 seconds. Pausing the automation, correcting its target to a UUID, and restarting Desktop eliminated the retry loop and returned CPU to idle. See the root-cause and recovery comment. The original diagnostic narrative below is retained as historical evidence but its route-parsing conclusion is superseded.
Environment
- OS: Windows 10 Home 22H2, build 19045.6466, x64
- Codex/ChatGPT Desktop release reported in logs: 26.707.72221
- Microsoft Store package: OpenAI.Codex_26.707.9981.0_x64
- CPU: 16 logical processors
- RAM: 31.9 GB total, about 17.7 GB free during reproduction
- C: about 129.5 GB free
- Agent environment: Windows native / PowerShell
Summary
Immediately after a Windows reboot and Codex Desktop launch, the Electron browser-main process sustained roughly one logical core of CPU and showed large memory churn. The Desktop log shows that the root route /index.html was repeatedly interpreted as the literal conversation ID thread.
The app repeatedly issued thread/read and thread/resume for conversationId=thread. The app server correctly rejected those requests because thread is not a UUID. The retry loop continued for about 13 minutes 44 seconds, then stopped after navigation to a valid UUID thread.
Process evidence
- Hot process:
ChatGPT.exe, PID 8504, Electron rolebrowser-main codex.exeapp-server itself was not the hot process- 8-second sample: 90.0% of one logical core
- separate 15-second quiet sample: 88.1% of one logical core
- peak private/pagefile bytes: about 2.16 GB
- peak working set: about 2.18 GB
- after the retry loop ended, a 10-second sample was 0.2% of one logical core and private memory was about 245 MB
- cumulative CPU after 21.4 minutes: 794.2 CPU-seconds
Desktop log evidence
Log file:
%LOCALAPPDATA%\Codex\Logs\2026\07\15\codex-desktop-ecb701c5-af90-4a7d-9f78-12e96caf9609-8504-t0-i1-154108-0.log
Launch:
2026-07-15T15:41:08.438Z info Launching app ... platform=win32
Retry-loop signature:
maybe_resume_started conversationId=thread ... routePath=/index.html
Request failed conversationId=thread ... method=thread/read ...
invalid thread id: ... found `t` at 1
Failed to read thread metadata before resume conversationId=thread ...
Request failed conversationId=thread ... method=thread/resume ...
invalid session id: ... found `t` at 1
heartbeat_automation_resume_failed ... threadId=thread
Counts in this single launch:
maybe_resume_started conversationId=thread 179
Failed to read thread metadata before resume conversationId=thread 179
heartbeat_automation_resume_failed 179
method=thread/read 366
method=thread/resume 359
invalid-ID-related log lines 1259
Timeline:
first invalid-ID line: 2026-07-15T15:41:15.578Z
last invalid-ID retry: 2026-07-15T15:55:19.054Z
This is about one retry cycle every 4–5 seconds. The rate was stable at roughly 70–99 matching lines per minute.
Controls / confounders checked
- The persisted global state did not contain a key or value equal to
thread. heartbeat-thread-permissions-by-idcontained 108 keys, all valid UUIDs.thread/listresponses completed in 23 ms to 2.5 s; they did not remain pending for the duration of the high-CPU period.- Bundled plugin reconciliation completed after about 2.5 minutes, while the invalid-ID retry continued for about 14 minutes.
- System memory and disk free space were not exhausted.
- GPU and renderer child processes were not the sustained hot process.
The profile is large and may amplify the problem:
active rollout files: 1629
active rollout size: 5.18 GB
archived rollout files: 217
archived rollout size: about 0.57 GB
state_5.sqlite threads: 1836 total / 1620 active
active thread title+preview+first_user_message: about 5.99 million characters
logs_2.sqlite: about 618 MB
prompt history: 299 entries / about 1.39 MB
However, the persisted state contains no invalid thread ID, and the retry loop itself is directly visible in the Electron main log.
Minimal reproduction
- Reboot Windows.
- Launch Codex Desktop.
- Leave the app on the initial/root route before a valid thread UUID is selected.
- Observe the main
ChatGPT.exeprocess in Task Manager or sample its CPU. - Inspect the Desktop main log under
%LOCALAPPDATA%\Codex\Logs\.... - Observe repeated
conversationId=thread,thread/read,thread/resume, andheartbeat_automation_resume_failedmessages. - Navigate to a valid existing thread. In this reproduction, the invalid-ID loop stopped shortly afterward and CPU returned to idle.
Expected behavior
The root/no-active-thread route must not be interpreted as a thread ID. Desktop should validate a conversation ID as a UUID before calling thread/read, thread/resume, or heartbeat automation resume. A failed invalid-ID request should not schedule an unbounded retry.
Actual behavior
Desktop repeatedly treats the route token thread as an actual conversation/session ID and retries every few seconds, consuming sustained CPU and causing large memory churn for approximately 14 minutes.
Related issues
- #30021: Windows main process burns a CPU core while visible and idle
- #31531: Windows 10 high CPU/disk after update
- #20864: session-directory/history scalability
- #24510: unbounded active-thread metadata and history/list processing
- #33169: 26.707.72221 freezes when accessing current threads
I can provide the complete Desktop log and share the diagnostic Codex session privately through in-app feedback.
6 Comments
Root cause correction and successful recovery
Further investigation found that the original
/index.htmlroute-parsing diagnosis was incorrect. The root route was present in the retry logs, but it was not the source of the literalthreadvalue.The invalid value originated from a heartbeat automation created in Codex session
019f5836-8afe-7091-956e-219f62f903b1at2026-07-15T14:57:52.246Z. The recorded tool call was:The tool accepted the request and persisted:
The tool schema available to the agent says to use
destination="thread"for the current local thread instead of inventing or copying a raw thread ID. The agent emitted the wrong field/value, but the automation API did not validate thattargetThreadIdwas a UUID before saving it.On subsequent Desktop launches, the heartbeat scheduler loaded this automation, reported:
and then repeatedly attempted
thread/readandthread/resumefor the invalid ID every approximately 4–5 seconds. This drove the Electron browser-main process to roughly one logical core and caused the memory churn reported above.This indicates two product-side safeguards are needed:
targetThreadIdvalues when creating or updating heartbeat automations.Recovery confirmation
I changed only this automation to
status = "PAUSED", corrected its persisted target to the actual UUID, and fully restarted Codex Desktop.After restart:
conversationId=thread,threadId=thread, or matching automation retry lines;This successful recovery strongly confirms the malformed heartbeat automation as the cause of the original performance problem.
A brief visual flicker remained only during startup while the bundled plugin marketplace reconciled from 6 plugins to 5 and back to 6, including two transient missing Browser-plugin image warnings. It settled and did not reproduce the CPU loop; that appears to be a separate startup issue.
Additional independent Windows reproduction: literal
currentI independently reproduced the same product-side validation/retry failure on Codex Desktop for Windows, but with the persisted heartbeat target set to the literal value
currentrather thanthread. This suggests the issue is not specific to one placeholder value: arbitrary non-UUID heartbeat targets can be accepted and then retried indefinitely.Environment
OpenAI.Codex_26.707.8479.0_x64__2p2nqsd0c76g0Persisted automation state
The active heartbeat automation contained:
Retry-loop evidence
Across the four Desktop log files belonging to one launch (
ChatGPT.exePID 15408), a sanitized recount found:The repeating sequence was:
The app continued to report the main window as responsive, but the Electron main process accumulated substantial CPU time and the user experienced repeated stalls/interruption. System RAM and disk were not exhausted during diagnosis.
Recovery confirmation
Deleting the malformed heartbeat through the supported automation manager and restarting Codex stopped new invalid-ID errors. No raw automation file was edited, and no credentials, account identifiers, thread UUIDs, or full logs are included here.
This independent reproduction supports the two safeguards already proposed in this issue:
targetThreadIdat automation create/update time.thread/readandthread/resumeafter a permanent invalid-target validation error.I can provide additional redacted log excerpts if maintainers need them.
Independent confirmation on 26.730.8199.0: literal
current, fixed live by rebindingThis was a naturally occurring incident; I did not attempt to reproduce it.
Environment
OpenAI.Codex 26.730.8199.0ChatGPT.exe:151.0.7922.71Creation-path evidence
The heartbeat was created through the supported
automation_updatetool with the caller-supplied value:The call returned success and persisted an ACTIVE automation with:
The tool guidance prefers
destination="thread"for the current local thread, so the caller supplied the wrong field/value. However, the create boundary accepted and persisted the non-UUID target.Observed behavior
The same Desktop process then repeatedly emitted:
thread/read -> invalid thread idthread/resume -> invalid session idheartbeat_automation_resume_failedthread_hydrationIn the completed desktop log,
thread/readandthread/resumeeach failed 2,607 times. The retry sequence occurred approximately every 2 seconds.A pre-fix sample of the stable main
ChatGPT.exePID showed:There was no corresponding process restart or
git.exe/taskkill.exechild-process storm.Recovery/control
I changed only the heartbeat target to the UUID of its existing thread through the supported automation update path. The automation remained ACTIVE and retained its name, prompt, and daily schedule. No thread/history reset and no app restart were required.
Immediately after rebinding:
This isolates the trigger to malformed heartbeat target metadata rather than the scheduled workload itself, and confirms that the validation/retry failure is still present in
26.730.8199.0.Suggested safeguards:
This does not imply that every Windows performance report has the same cause, but it is an independently confirmed instance of this specific failure mode.
Independent reproduction on 26.803.5235.0: literal
current, sustained CPU, and pointer stutterThis is another naturally occurring Windows reproduction. I have not modified the affected automation yet, so the measurements below are pre-recovery.
Environment
OpenAI.Codex 26.803.5235.0(package status OK)Persisted automation state
An ACTIVE heartbeat created through the supported automation path was accepted and persisted with:
No automation prompt, account data, local paths, or thread UUIDs are included here.
Natural before/after cutover in the same Desktop process
This incident provides a clean creation-time boundary:
heartbeat_automation_resume_failedevents2026-08-07T18:08:53.243Zinvalid thread iderror appeared at18:08:53.272Z, 29 ms laterThis strongly isolates the trigger to the malformed heartbeat metadata rather than a cold-start-only condition.
Reproduction across launches
The same loop is present in the most recent 15 Desktop launches. On the current launch:
maybe_resume_startedbegan about 4.4 s after launchheartbeat_automation_resume_failedevents (~36/min)thread/read -> invalid thread idthread/resume -> invalid session idthread_hydrationResource and process evidence
During a quiet 15-second sample:
ChatGPT.exe: 9.578 CPU-s / 15 s (~63.9% of one core)codex.exe: 1.469 CPU-s / 15 s (~9.8% of one core)A separate 15-second process-start sample observed:
BrowserUseThreadConfig browser_use_runtime_paths_selectedeventsnode.exeprocesses directly parented by the mainChatGPT.exe, with matchingconhost.exechildrenThe timestamps align one-for-one within the sample window. I am reporting this as an observed correlation; I did not capture the short-lived Node command lines.
Expected behavior
targetThreadIdvalues at create/update time.I can add a post-rebind CPU/error/process comparison after applying the supported recovery path.
Recovery confirmation: deleting the malformed heartbeat stops the loop immediately
I deleted only the affected heartbeat through the supported automation manager. No raw automation file was edited, and the Desktop app was not restarted.
A 20-second post-delete control window showed:
heartbeat_automation_resume_failedevents: 0invalid thread idevents: 0invalid session idevents: 0BrowserUseThreadConfigruntime-selection events: 0ChatGPT.exe: 0CPU comparison:
| Process | Before deletion | After deletion |
|---|---:|---:|
| main
ChatGPT.exe| 63.9% of one core | 1.0% || bundled
codex.exe| 9.8% | 0.8% || hottest renderer | 8.3% | 1.2% |
The automation file and directory were also removed by the supported manager. The retry/runtime/process churn stopped live, without a restart. This completes the natural before/after control and confirms the malformed ACTIVE heartbeat target as the cause of this incident.
Hi @Pluglug, I'm testing a local-first, read-only diagnostic tool (Codex Rescue Alpha5) against local session persistence and rollout anomalies. It evaluates schema compatibility, tool correlation, and state consistency without modifying the original rollout or SQLite databases.
If the affected session is still present locally, you can run:
No raw data is needed; please redact any private repository paths before sharing results.