Skip to content

Windows Desktop 26.707.72221: invalid heartbeat target thread is accepted and retried every 4–5s, causing high CPU #33371

Open

Description

@Pluglug

Important

Root-cause correction (2026-07-15): Subsequent investigation showed that /index.html was incidental, not the source of the literal thread value. A malformed heartbeat automation was created with targetThreadId: "thread", and the automation API accepted and persisted it as target_thread_id = "thread". Desktop then retried thread/read and thread/resume every 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 role browser-main
  • codex.exe app-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-id contained 108 keys, all valid UUIDs.
  • thread/list responses 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

  1. Reboot Windows.
  2. Launch Codex Desktop.
  3. Leave the app on the initial/root route before a valid thread UUID is selected.
  4. Observe the main ChatGPT.exe process in Task Manager or sample its CPU.
  5. Inspect the Desktop main log under %LOCALAPPDATA%\Codex\Logs\....
  6. Observe repeated conversationId=thread, thread/read, thread/resume, and heartbeat_automation_resume_failed messages.
  7. 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

I can provide the complete Desktop log and share the diagnostic Codex session privately through in-app feedback.

Activity

  1. added
    bugSomething isn't working
    appIssues related to the Codex desktop app
    windows-osIssues related to Codex on Windows systems
    app-serverIssues involving app server protocol or interfaces
    on Jul 15, 2026
  2. Pluglug commented on Jul 15, 2026

    @Pluglug
    Author

    Root cause correction and successful recovery

    Further investigation found that the original /index.html route-parsing diagnosis was incorrect. The root route was present in the retry logs, but it was not the source of the literal thread value.

    The invalid value originated from a heartbeat automation created in Codex session 019f5836-8afe-7091-956e-219f62f903b1 at 2026-07-15T14:57:52.246Z. The recorded tool call was:

    automation_update({
      mode: "create",
      kind: "heartbeat",
      name: "monitor-pr-1299-review",
      rrule: "FREQ=MINUTELY;INTERVAL=10",
      status: "ACTIVE",
      targetThreadId: "thread"
    })

    The tool accepted the request and persisted:

    id = "monitor-pr-1299-review"
    kind = "heartbeat"
    status = "ACTIVE"
    rrule = "FREQ=MINUTELY;INTERVAL=10"
    target_thread_id = "thread"

    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 that targetThreadId was a UUID before saving it.

    On subsequent Desktop launches, the heartbeat scheduler loaded this automation, reported:

    Heartbeat automation skipped: thread missing
    automationId=monitor-pr-1299-review
    targetThreadId=thread
    

    and then repeatedly attempted thread/read and thread/resume for 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:

    1. Reject non-UUID targetThreadId values when creating or updating heartbeat automations.
    2. Do not schedule an unbounded rapid resume/read retry loop after an invalid or missing target-thread failure.

    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:

    • the new Desktop log contained zero conversationId=thread, threadId=thread, or matching automation retry lines;
    • a 12-second CPU sample showed all Codex/ChatGPT processes at effectively 0% of one logical core after startup settled;
    • browser-main private memory was approximately 215 MB and working set approximately 260 MB;
    • the sustained high-CPU loop did not recur.

    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.

  3. changed the title [-]Windows Desktop 26.707.72221: `/index.html` is treated as conversation ID `thread`, causing a 14-minute `thread/read` / `thread/resume` retry loop and high CPU[/-] [+]Windows Desktop 26.707.72221: invalid heartbeat target `thread` is accepted and retried every 4–5s, causing high CPU[/+] on Jul 15, 2026
  4. hsps73 commented on Jul 26, 2026

    @hsps73

    Additional independent Windows reproduction: literal current

    I 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 current rather than thread. This suggests the issue is not specific to one placeholder value: arbitrary non-UUID heartbeat targets can be accepted and then retried indefinitely.

    Environment

    • Windows x64
    • Affected Microsoft Store package: OpenAI.Codex_26.707.8479.0_x64__2p2nqsd0c76g0
    • Incident date: 2026-07-13 to 2026-07-14

    Persisted automation state

    The active heartbeat automation contained:

    kind = "heartbeat"
    status = "ACTIVE"
    target_thread_id = "current"

    Retry-loop evidence

    Across the four Desktop log files belonging to one launch (ChatGPT.exe PID 15408), a sanitized recount found:

    invalid session/thread operational log lines: 30,842
    heartbeat_automation_resume_failed lines:       7,705
    first matching error: 2026-07-13T12:53:47.256Z
    last matching error:  2026-07-13T23:54:06.511Z
    duration:             11.01 hours
    

    The repeating sequence was:

    method=thread/resume ... invalid session id ... threadId=current
    heartbeat_automation_resume_failed ... threadId=current
    method=thread/read ... invalid thread id ... conversationId=current
    Failed to read thread metadata before resume ... conversationId=current
    

    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:

    1. Reject any non-UUID targetThreadId at automation create/update time.
    2. Stop retrying thread/read and thread/resume after a permanent invalid-target validation error.

    I can provide additional redacted log excerpts if maintainers need them.

  5. Linkouswxs commented on Aug 7, 2026

    @Linkouswxs

    Independent confirmation on 26.730.8199.0: literal current, fixed live by rebinding

    This was a naturally occurring incident; I did not attempt to reproduce it.

    Environment

    • Windows x64
    • Microsoft Store package: OpenAI.Codex 26.730.8199.0
    • Bundled ChatGPT.exe: 151.0.7922.71

    Creation-path evidence

    The heartbeat was created through the supported automation_update tool with the caller-supplied value:

    targetThreadId: "current"

    The call returned success and persisted an ACTIVE automation with:

    target_thread_id = "current"

    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 id
    • thread/resume -> invalid session id
    • heartbeat_automation_resume_failed
    • source: thread_hydration

    In the completed desktop log, thread/read and thread/resume each failed 2,607 times. The retry sequence occurred approximately every 2 seconds.

    A pre-fix sample of the stable main ChatGPT.exe PID showed:

    • CPU time: 7.89 seconds over 15 seconds
    • working set: approximately 1.19–2.00 GB
    • working-set swing: approximately 810–820 MB
    • continuous UI stutter during typing and task switching

    There was no corresponding process restart or git.exe / taskkill.exe child-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:

    • invalid read/resume errors: 0 in the post-fix log window
    • main-process CPU time: 0.61 seconds over 20 seconds
    • working set: 272.8–274.8 MB
    • working-set swing: approximately 2 MB
    • the user confirmed that the UI stutter disappeared

    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:

    1. Reject or normalize non-UUID heartbeat targets at create/update time.
    2. Resolve the current-thread destination to a real thread UUID before persistence.
    3. Treat an invalid/missing target as a permanent failure; use bounded retry/backoff or a circuit breaker.
    4. Automatically pause/quarantine the broken automation and surface an actionable warning in Scheduled instead of retrying indefinitely.

    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.

  6. catchitin commented on Aug 8, 2026

    @catchitin

    Independent reproduction on 26.803.5235.0: literal current, sustained CPU, and pointer stutter

    This is another naturally occurring Windows reproduction. I have not modified the affected automation yet, so the measurements below are pre-recovery.

    Environment

    • Windows 11 Home 25H2, build 26200.8973, x64
    • Microsoft Store package: OpenAI.Codex 26.803.5235.0 (package status OK)
    • CPU: Intel Core i7-11700F, 16 logical processors
    • RAM: 32 GB
    • GPU: RTX 3070, NVIDIA 610.74
    • Symptom: after every Codex Desktop launch, mouse-pointer movement becomes visibly choppy

    Persisted automation state

    An ACTIVE heartbeat created through the supported automation path was accepted and persisted with:

    kind = "heartbeat"
    status = "ACTIVE"
    target_thread_id = "current"

    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:

    • before the automation was created: 0 invalid thread/session ID events and 0 heartbeat_automation_resume_failed events
    • the automation tool returned success at 2026-08-07T18:08:53.243Z
    • the first invalid thread id error appeared at 18:08:53.272Z, 29 ms later
    • after creation in that same process: 4,100 invalid-ID events and 1,025 heartbeat-resume failures

    This 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_started began about 4.4 s after launch
    • invalid thread/session requests began about 5–8.5 s after launch
    • over a 469-second window:
      • 284 heartbeat_automation_resume_failed events (~36/min)
      • 1,318 error-level log entries (~169/min)
      • repeated thread/read -> invalid thread id
      • repeated thread/resume -> invalid session id
      • source: thread_hydration

    Resource and process evidence

    During a quiet 15-second sample:

    • main ChatGPT.exe: 9.578 CPU-s / 15 s (~63.9% of one core)
    • bundled codex.exe: 1.469 CPU-s / 15 s (~9.8% of one core)
    • renderer: 1.250 CPU-s / 15 s (~8.3% of one core)
    • WMI provider, Defender, DWM, and the measured GPU process were idle or near zero
    • DPC/interrupt, disk latency, available RAM, USB/PnP, and Windows event logs showed no synchronized system fault

    A separate 15-second process-start sample observed:

    • 9 heartbeat failures
    • 9 BrowserUseThreadConfig browser_use_runtime_paths_selected events
    • 8 short-lived node.exe processes directly parented by the main ChatGPT.exe, with matching conhost.exe children

    The 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

    1. Reject or normalize non-UUID targetThreadId values at create/update time.
    2. Resolve the current-thread destination to a real UUID before persistence.
    3. Treat invalid/missing targets as permanent failures with bounded retry/backoff.
    4. Do not repeat Browser runtime discovery/process startup on each permanent heartbeat failure.
    5. Pause/quarantine the malformed automation and surface an actionable warning.

    I can add a post-rebind CPU/error/process comparison after applying the supported recovery path.

  7. catchitin commented on Aug 8, 2026

    @catchitin

    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:

    • new heartbeat_automation_resume_failed events: 0
    • new invalid thread id events: 0
    • new invalid session id events: 0
    • new BrowserUseThreadConfig runtime-selection events: 0
    • processes started directly by the main ChatGPT.exe: 0
    • Desktop main log growth: 3 lines total in 20 seconds

    CPU 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.

  8. boombx403-byte commented on Aug 18, 2026

    @boombx403-byte

    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:

    pip install codex-rescue==0.1.0a5
    codex-rescue doctor --latest

    No raw data is needed; please redact any private repository paths before sharing results.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    appIssues related to the Codex desktop appapp-serverIssues involving app server protocol or interfacesautomationsbugSomething isn't workingperformancewindows-osIssues related to Codex on Windows systems

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions