Remote Control active task causes duplicate internal message delivery on Windows

Open 💬 3 comments Opened Aug 1, 2026 by kumag36

Summary

On Codex Desktop for Windows, an internal task-to-task message can be delivered twice when a Remote Control client (iPhone or iPad) has the destination task actively open.

The first delivery is local. A second delivery arrives through the enrolled Remote Control host route with a different message ID. This can duplicate callbacks and potentially repeat downstream actions.

Environment

  • Windows Codex Desktop
  • Bundled Codex CLI observed: 0.146.0-alpha.9.2
  • Remote clients tested: ChatGPT/Codex on iPhone and iPad
  • One Windows host enrolled in Remote Control

Deterministic reproduction

  1. Enroll one iPhone or iPad as a Remote Control client.
  2. On the mobile client, open the destination Codex task (opening the task is sufficient; sending a mobile message is not required).
  3. From another local Codex task, send one internal message to the destination task using the calling-host/default route (host omitted).
  4. Observe two distinct user-message records in the destination task:
  • one normal local delivery;
  • one Remote Control-wrapped delivery from the enrolled host, with a different message ID.
  1. Return the mobile client to the task list or close the app. Repeat the send: only one delivery occurs.

A/B results

  • Zero remote clients: no duplicate.
  • One enrolled client that has not opened the destination task: no duplicate.
  • Two enrolled clients that have not opened it: no duplicate.
  • iPhone alone actively viewing destination task: duplicate.
  • iPad alone actively viewing destination task: duplicate.
  • Mobile app open only at task list: no duplicate.
  • Desktop showing another task while mobile alone views destination: duplicate.
  • Explicitly targeting hostId=local for the receiving task: no duplicate.
  • Omitting the recipient host while the remote client views the task: duplicate reproduced.

In the isolation test, local delivery occurred first and the Remote Control copy arrived about 16.7 seconds later. In other active-task trials the second copy sometimes arrived within milliseconds.

Expected behavior

A single internal send should create one logical delivery regardless of whether a Remote Control client is subscribed to the destination task. Remote Control fan-out should not reinsert the same message as a second user message.

Actual behavior

The same payload is persisted twice with distinct message IDs through local and Remote Control routes.

Temporary mitigation

For local destination tasks, explicitly setting hostId=local prevents the duplicate in the tested environment. A stored Remote Control host ID should not be used as send-time routing authority for a local task.

Impact

Duplicate callbacks can cause duplicate processing, repeated external actions, misleading audit trails, or unnecessary no-retry/HOLD recovery flows. The behavior also depends on whether a mobile client currently has the task open, making it difficult to detect.

I can provide sanitized timestamps and additional logs privately if needed. Internal thread IDs, host IDs, and account identifiers are intentionally omitted here.

View original on GitHub ↗

3 Comments

kumag36 · 22 days ago

Additional diagnostic evidence from a later recurrence:

I currently suspect that stale TCP connections in the Desktop app-server may be contributing to this issue.

During the failure state, the owning codex.exe app-server process had three IPv6 TCP connections remaining in CLOSE_WAIT. The Codex processes were still responsive, and no corresponding Windows application crash, reliability failure, or network disconnect event was found.

After restarting Codex Desktop—but not Windows—the CLOSE_WAIT connections disappeared. A task-message round trip then succeeded while the iPhone app was closed.

Environment for this observation:

  • Codex Desktop: 26.727.6591.0
  • Windows Desktop app-server launched as codex.exe ... app-server --analytics-default-enabled
  • Desktop restart only; the PC was not rebooted

This is a correlation and working hypothesis, not a confirmed root cause. On the next recurrence, I plan to capture the same diagnostics before recovery and then try restarting only the affected Desktop app-server process, identified from the connection's owning PID, parent process, and command line. The goal is to determine whether this minimal restart clears the stale connections and restores task delivery without restarting the entire Desktop app.

This may also be related to the host-routing/result ambiguity reported in #35394, although the causal relationship is currently unverified.

kumag36 · 20 days ago

Follow-up diagnostic update (2026-08-08 JST)

This is additional correlation evidence, not a confirmed root cause.

  • After a full Codex Desktop restart, the global codex.exe ... app-server Code Mode host initially had CLOSE_WAIT=0.
  • About 17 minutes later, the same host had CLOSE_WAIT=3 (while 6 connections remained established). This was observed without a Windows reboot.
  • Around the recurrence, task-list/metadata reads could still work, while an ordinary COO -> PM task message returned an error and a bounded PM readback waited without a usable result. A later one-line, no-op route smoke from the same COO context was accepted and reached PM. This looks intermittent or conditional rather than a total outage.
  • A separate Sebas -> PM no-op smoke also completed. Therefore the observation does not establish that either the COO task or PM task was permanently broken.

Important boundaries / unknowns:

  • We have not established that closing the iPhone app is the cause. The working hypothesis is broader: desktop/mobile Remote Control connection transitions may interact with app-server transport state. The original active-mobile-task duplicate reproduction remains the stronger A/B result for the duplicate-delivery symptom.
  • The CLOSE_WAIT sockets belonged to the global desktop Code Mode host process, not an individual task. There is no known supported way to safely terminate only one such socket or one affected task while preserving the rest of the Code Mode session.
  • Restarting the whole Desktop app cleared the observed CLOSE_WAIT state at startup, but did not prove a durable fix: later task-message behavior was still intermittent.

Current environment:

  • Codex Desktop 26.727.6591.0 on Windows
  • Code Mode host: bundled codex.exe ... app-server

Useful product-side diagnostic direction: expose connection/transport health and reconnect events per logical task-message send, including whether a Remote Control route participates, without requiring users to inspect process sockets. Sanitized timestamps and before/after socket snapshots can be supplied if useful.

kumag36 · 20 days ago

Suggested product-side fix / acceptance criteria

The immediate bug should be addressed at the message-delivery boundary, rather than by asking users to choose a host manually or restart the Desktop app.

  1. Coalesce an exact logical send before it becomes a second task message.
  • Give each internal task-to-task send a stable logical delivery ID.
  • If local delivery and Remote Control fan-out represent the same logical delivery, persist/render it once in the destination task.
  • Keep transport receipts for diagnostics, but do not create a second user-message record.
  • Do not coalesce if payload, sender, recipient, or logical delivery ID differs; surface that as a conflict instead.
  1. Separate delivery state from UI/client subscription state.
  • Opening the destination task on iPhone/iPad must not alter the routing authority for a local Desktop-to-Desktop internal send.
  • The calling-host/default local route should remain valid regardless of which Remote Control clients are viewing the task.
  1. Make send outcomes observable and bounded.
  • Return a structured result such as accepted / receiver-claimed / failed / unknown, plus the logical delivery ID.
  • Do not expose a send as accepted when only a transport attempt has occurred.
  • If the app-server transport is unhealthy, fail within a bounded time with a diagnostic reason instead of leaving a task-message call waiting indefinitely.
  1. Add safe transport recovery.
  • Detect stale or accumulating transport connections in the Desktop Code Mode host and reconnect only the affected transport/app-server component where safe.
  • Preserve active task context and prevent replay of an already accepted logical delivery after reconnect.
  • A user should not need to inspect Windows CLOSE_WAIT sockets or restart the entire Desktop app as the ordinary recovery path.

Suggested acceptance test:

  • With iPhone and/or iPad enrolled and actively viewing the destination task, 100 consecutive internal sends from a local Desktop task produce exactly 100 logical destination messages, no duplicate user-message records, and no manual host selection.
  • Toggle Remote Control client open/background/closed states during the run; results remain exactly-once at the logical-message level.
  • Simulate a transport reconnect/stale connection: either the send completes once with receiver claim, or returns a bounded explicit failure. It must not hang indefinitely or later replay as a duplicate.

This would address both the duplicate-delivery symptom and the later intermittent send/readback symptom without turning the user into the recovery mechanism.