Skip to content

Desktop thread tools intermittently lose handlers (No handler registered) within an active session #28080

Open

Description

@Hogna67

What version of the Codex App are you using?

Codex Desktop 26.608.1337.0 on Windows.

Bundled / installed CLI observed during the investigation: codex-cli 0.128.0.

What platform is your computer?

Windows 11 x64.

What issue are you seeing?

During an active Codex Desktop session, official thread-management tools intermittently lose their registered handlers and start returning errors such as:

No handler registered for tool: read_thread
No handler registered for tool: set_thread_title
No handler registered for tool: set_thread_archived

This happens even though the same tools were available and working earlier in the same Desktop session.

In the affected workflow, these tools are used to manage UI-visible notification worker threads:

  • inspect whether a worker thread is idle or stuck (read_thread)
  • rename threads to reflect active / standby / retired state (set_thread_title)
  • archive retired worker threads (set_thread_archived)

When handlers disappear, the automation can still update durable route files, but it cannot reliably clean up or relabel the Desktop UI. This leaves stale/retired worker threads visible and makes the session state misleading.

What steps can reproduce the bug?

This is intermittent, but the observed sequence was:

  1. Use Codex Desktop on Windows with a project thread open.
  2. Use the official thread-management tools successfully earlier in the session, e.g. set_thread_title and set_thread_archived.
  3. Continue normal agent work involving background/heartbeat-related notification routing.
  4. Later in the same session, call read_thread for a known thread.
  5. Observe:
No handler registered for tool: read_thread
  1. Attempt to recover by using other thread-management tools.
  2. Observe:
No handler registered for tool: set_thread_title
No handler registered for tool: set_thread_archived

The tools are still exposed to the model/tool layer, but the Desktop-side handler is unavailable.

What is the expected behavior?

  • If Desktop exposes read_thread, set_thread_title, and set_thread_archived, their handlers should remain registered and callable for the active session.
  • If a plugin/app-server bridge is temporarily unavailable, Desktop should reinitialize it or return a structured recoverable error with a suggested recovery path.
  • Tool discovery should not advertise tools whose handlers are not currently registered.
  • Thread-management failures should not require restarting Codex Desktop or manual UI cleanup.

Additional information

This may be related to Desktop/app-server subscription or target-thread state issues, but it is not exactly the same symptom as the heartbeat target resume loop described in #19563.

It may also be related to UI-visible notification delivery/tool-call state problems reported separately in #28070, where thread delivery side effects and Desktop UI state can diverge.

Operational impact: workflows that depend on official thread tools for failover/cleanup can update backend files correctly, but cannot make the Desktop UI match reality when handlers disappear.

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
    tool-callsIssues related to tool calling
    on Jun 13, 2026
  2. github-actions commented on Jun 13, 2026

    @github-actions
    Contributor

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

    Powered by Codex Action

  3. Hogna67 commented on Jun 13, 2026

    @Hogna67
    Author

    Additional observation from the same Windows Desktop session:

    While testing a recovery path that should wake the current thread via a heartbeat automation, the automation tool handler also disappeared:

    No handler registered for tool: automation_update
    

    This happened after other thread-management tools had already returned similar errors (read_thread, set_thread_title, set_thread_archived).

    Operationally, this blocks a safe repair workflow: when a notification worker thread appears stuck, the background watchdog can write a repair queue, but it cannot reliably create/update a heartbeat to wake the coordinating thread because automation_update itself may have no registered handler.

    A raw automation.toml written to $CODEX_HOME/automations/<id>/automation.toml did not fire within a 75 second smoke-test window, so using the official automation tool seems necessary, but the handler was unavailable.

  4. aemilcar commented on Jul 3, 2026

    @aemilcar

    I observed a related failure on macOS in Codex Desktop, with codex_app.read_thread_terminal specifically.

    Environment:

    • Codex bundled CLI: codex-cli 0.142.3
    • Platform: macOS 26.5.1
    • Architecture: arm64
    • Surface: Codex Desktop app

    Observed behavior:

    • The app tool codex_app.read_thread_terminal was exposed/callable to the agent.
    • When invoked, the agent loop blocked for approximately 9h 25m.
    • The call eventually returned:
    No handler registered for tool: read_thread_terminal
    

    This was not a long-running shell/test process. The local command the agent was trying to inspect had completed much earlier; the agent was suspended waiting on the app tool call.

    Why this seems related:

    • The tool was visible to the model/tool layer, but the Desktop-side handler was unavailable.
    • The failure did not fail fast.
    • The UI made it hard to tell that the agent was blocked on an app tool dispatch rather than on terminal/test execution.

    Expected behavior:

    • If a Desktop app tool is exposed, its handler should be registered and callable.
    • If the handler is unavailable, the call should fail fast with a recoverable error.
    • Long-running app tool calls should have a watchdog/timeout or visible blocked-on-tool state.
    • Tool-dispatch waits should be distinguishable from shell/process waits in diagnostics.

    I am intentionally omitting session IDs, local paths, raw logs, and project details because this is a public issue.

  5. johnsilvavlogs commented on Jul 10, 2026

    @johnsilvavlogs

    Additional macOS reproduction on the current latest Desktop build, including a recovery boundary that may help isolate the handler lifecycle.

    Environment:

    • ChatGPT/Codex Desktop 26.707.31428, build 5059
    • bundled CLI codex-cli 0.144.0-alpha.4
    • global CLI codex-cli 0.144.1
    • macOS 26.5.2 (25F84), arm64

    Observed in a long-running Desktop manager thread that had successfully used the official thread tools earlier:

    • The tools remained advertised to the model, but calls to list_projects, list_threads, create_thread, set_thread_title, and read_thread_terminal stopped returning.
    • Repeated bounded waits of 60-150 seconds produced neither a result nor a structured error.
    • A timed-out create_thread call did not create a child in this reproduction; I checked both current thread state and recent rollout/session records before retrying.
    • Normal model turns, shell commands, goal state, and GitHub connector tools continued working. The Desktop app-server remained alive, and a process sample showed the code-mode host idle/waiting rather than CPU-spinning.
    • state_5.sqlite passed PRAGMA integrity_check.

    Recovery boundary:

    • I did not restart or modify the app/database because active threads needed preservation.
    • On the next fresh user turn in the same thread, list_projects and list_threads immediately returned successfully again.
    • The manager title/pin handlers also worked after that turn boundary.

    This looks like an advertised-handler/bridge state that can be lost within a turn and rehydrated by a fresh user turn, rather than a permanently dead app-server. A fail-fast watchdog plus explicit handler re-registration at turn/resume boundaries would avoid multi-minute/indefinite stalls. create_thread should also return an explicit delivered/not-delivered/uncertain operation state so retries remain safe.

    Separate observation, not claimed as causal: this profile's logs_2.sqlite is about 3.9 GB with a large freelist; that lifecycle is already covered by #30431.

  6. ttrias commented on Jul 11, 2026

    @ttrias

    Cross-reference: #32294 appears to be the automation-specific form of this handler-registration problem.

    In #32294, codex_app.automation_update remained exposed in the tool catalog while calls failed with No handler registered for tool: codex_app.automation_update. The same thread later succeeded without changing its persisted automation TOML. There is also a source correlation: the failing turn lacked a recorded client_id, while the later successful Desktop turn had one.

    The shared failure mode is tool discovery and Desktop handler availability diverging. The automation variant can strand persistent scheduled state because the supported pause/update/delete path becomes unavailable.

  7. jtcchan commented on Jul 16, 2026

    @jtcchan

    One additional source-level correlation for this handler-loss symptom: the packaged Desktop renderer's dynamic-tool dispatcher awaits the selected handler with no outer timeout, and only sends the mcp-response after that promise settles. A lost/stale/non-settling handler dependency can therefore leave a visible tool call pending indefinitely rather than returning No handler registered or another retryable error.

    A later retry of the previously blocked tasks succeeded, consistent with a transient registration/renderer-activation boundary. The fuller timing, focus-state, and fix recommendations are documented in #31584 (comment).

  8. quiezent commented on Jul 21, 2026

    @quiezent

    Additional Windows reproduction on Desktop 26.715.7063

    I reproduced this on 2026-07-21 with a substantially newer Windows Desktop build.

    Environment

    • OpenAI.Codex / ChatGPT Desktop: 26.715.7063.0
    • Bundled CLI: codex-cli 0.145.0-alpha.18
    • Windows 11 x64
    • Local Desktop project thread

    Observed

    The live deferred tool registry advertised all 15 codex_app__* tools, but calls returned:

    No handler registered for tool: list_projects
    No handler registered for tool: list_threads
    No handler registered for tool: read_thread
    No handler registered for tool: read_thread_terminal
    No handler registered for tool: load_workspace_dependencies
    No handler registered for tool: automation_update
    No handler registered for tool: send_message_to_thread
    

    Normal shell calls, GitHub/connector tools, and the separate collaboration/subagent route continued to work, so this was not a general model turn or app-server outage. A separately spawned diagnostic agent using the same Desktop bridge reproduced the read-only handler failures.

    Update/restart boundary

    1. I performed a complete Codex process shutdown and relaunch.
    2. I then installed the already-downloaded update through the app's own Update control.
    3. Windows successfully switched the registered package from 26.715.4045.0 to 26.715.7063.0, and the new main process was independently verified.
    4. On the next fresh user turn in the existing affected thread, the same handler errors remained.

    Thus, for this reproduction, a verified application update plus full process restart did not rehydrate the existing thread's Desktop handlers. This is consistent with a persisted per-thread/bridge-state problem, although I have not yet run the stronger control of creating a brand-new user-visible local task under the new build.

    Side-effect reconciliation

    I made exactly one send_message_to_thread call to a user-authorized idle test thread and did not retry it. It returned the handler error. I then checked the target rollout directly: its line count and last-write timestamp were unchanged, and the diagnostic text was absent. Therefore this particular failure did not deliver, unlike the uncertain-delivery behavior reported in #29886.

    This reinforces the need for explicit delivered / not_delivered / unknown semantics and for callers not to retry side-effecting thread tools blindly.

    Local paths, account data, and thread IDs are intentionally omitted.

  9. DKWien commented on Jul 26, 2026

    @DKWien

    Confirming quiezent’s reproduction on an even newer Windows build: I can reproduce the same handler-registration failure on Codex Desktop 26.721.4979.0.

    The affected tools were exposed as available, but invoking them returned:

    • No handler registered for tool: list_projects
    • No handler registered for tool: list_threads
    • No handler registered for tool: fork_thread

    The failure occurred while Codex was trying to inspect the current project/thread state and create a successor task in the same project.

    I fully restarted Codex Desktop and repeated the calls, but all three tools continued to return the same errors. In this occurrence, the problem therefore persisted across an application restart.

    Impact: automatic workflow continuation and successor-task reconciliation were blocked, requiring manual intervention. No repository data was lost.

    I have also submitted this through /feedback.
    Feedback reference: 019f9f51-f7f2-7b91-8f3e-ed7145bcc0e1

  10. quiezent commented on Jul 27, 2026

    @quiezent

    Controlled Windows reproduction: handler loss, false-negative delivery, and fresh-turn recovery

    Reproduced on 2026-07-27 in a newly created local Desktop task, not a legacy task.

    Environment

    • OpenAI.Codex Desktop: 26.721.4979.0
    • Bundled CLI: codex-cli 0.146.0-alpha.3.1
    • Windows 11 x64
    • The same app process remained running throughout; no restart or update occurred during this sequence.

    Baseline

    The new coordinator task had already completed a four-task, six-pair messaging mesh. send_message_to_thread, read_thread, and wait_threads had all worked earlier in the same task/session.

    Exact sequence (UTC)

    1. 14:26:56.660 — send_message_to_thread called once for a local manager task.

    2. 14:26:57.218 — caller received:

      No handler registered for tool: send_message_to_thread
      
    3. Target rollout nevertheless recorded the exact matching codex_delegation (including the expected source task and unique prompt token) at 14:27:00.959. The send therefore delivered despite the handler error.

    4. In a later turn, three sends succeeded at 14:31:48, 14:31:57, and 14:32:07.

    5. Immediately afterward in that same turn, wait_threads failed twice at 14:32:12.348 and 14:32:30.734 with:

      No handler registered for tool: wait_threads
      

      The second failure followed fresh tool discovery. This was tool-specific loss: send_message_to_thread had just succeeded while wait_threads had no handler.

    6. 14:52:32.804 — another single send_message_to_thread call was made to a different local manager task.

    7. 14:52:33.442 — caller again received No handler registered for tool: send_message_to_thread.

    8. Target rollout recorded the exact matching delegation at 14:52:33.827, only 385 ms later. This is a second confirmed false-negative delivery.

    9. A fresh diagnostic user turn at 14:59 (without restarting Desktop) successfully called both send_message_to_thread and read_thread; the return token arrived and the read succeeded.

    One early failing turn lacked a recorded client_id, but the later false-negative send and the wait_threads failures occurred in turns that did have client_id values. Missing client_id may correlate with some occurrences, but it is not necessary for this failure.

    What this narrows down

    This appears to combine #28080's transient advertised-handler loss with #29886's post-delivery acknowledgement failure:

    • It is not explained solely by old tasks having a frozen/missing tool manifest; this was a new task whose tools had already passed a full mesh.
    • It is not a complete app-server outage; ordinary turns and other tools continued.
    • Handler availability can differ by tool within one turn.
    • For send_message_to_thread, No handler registered is not a reliable not_delivered result. The side effect may already have occurred.
    • A fresh turn can rehydrate the handlers, but this is not a dependable recovery guarantee.

    Safety impact

    Blindly retrying a side-effecting task call after this error can duplicate work. Until the API distinguishes delivery from acknowledgement, the safest caller behavior is:

    1. send once with a unique nonce/idempotency token;
    2. on handler error, classify delivery as UNKNOWN, not failed;
    3. use read_thread to reconcile the exact source ID and nonce in the target;
    4. retry only after positive proof of non-delivery; if read_thread is also unavailable, stop and surface uncertainty.

    It would help if the tool returned explicit delivered, not_delivered, unknown, or delivered_but_ack_failed semantics plus a stable receipt/message ID, and if Desktop re-registered advertised handlers at every turn/resume boundary.

  11. DKWien commented on Jul 28, 2026

    @DKWien

    Additional Windows reproduction from a scheduled watcher

    Observed on 2026-07-28 with Codex Desktop 26.721.4979.0 on Windows 11 x64.

    This reproduction is specifically from a recurring local-project watcher whose first operation is a bounded thread snapshot:

    • list_threads(limit=20) was called once per scheduled invocation.
    • The project had fewer than 25 active/non-archived Codex tasks after older tasks had been archived.
    • Despite the reduced task count and bounded request, multiple scheduled invocations did not receive a usable thread snapshot within their timeout; another affected task received No handler registered for the same Desktop thread-tool family.
    • The same thread handlers later worked again from an interactive turn without any repository change.
    • When the snapshot succeeded, the watcher could take its intended fast path and stop without inspecting the repository.
    • When it did not succeed, the watcher had to classify task state as UNCLEAR and fail closed, so it could not safely reconcile or dispatch the already-reserved successor.

    This suggests the failure is not primarily caused by a large visible-thread set. Archiving reduced the enumeration workload but did not eliminate the handler/bridge failure.

    Operational impact: a safe scheduler cannot distinguish “no active worker” from “thread snapshot unavailable”, so autonomous continuation stalls even though local repository state and workflow reservations are valid. Retrying side-effecting calls remains unsafe because delivery/acknowledgement can be ambiguous; explicit delivered / not_delivered / unknown semantics and fail-fast availability reporting would help.

    I am omitting local paths, task IDs, account data, and raw session logs.

  12. hirsrsk commented on Aug 2, 2026

    @hirsrsk

    Additional Windows reproduction on Desktop 26.727.6591.0

    I observed the same advertised-tool/handler divergence on 2026-08-03 in a long-lived local Codex Desktop task.

    Environment

    • OpenAI.Codex / ChatGPT Desktop: 26.727.6591.0
    • Bundled app-server / CLI: 0.146.0-alpha.9.2
    • Windows x64
    • ChatGPT Pro

    Baseline

    The same task had successfully called the app-native thread-management tools multiple times earlier in the same Desktop session, including list_threads, read_thread, and wait_threads.

    Observed failure

    Later, without a user-initiated app restart, update, or settings change:

    1. read_thread returned:

      No handler registered for tool: read_thread
      
    2. An immediate list_threads call returned:

      No handler registered for tool: list_threads
      
    3. The runtime tool catalog still contained the canonical codex_app__read_thread, codex_app__list_threads, and related thread-tool definitions. Discovery/advertisement therefore remained present while the Desktop-side handlers were unavailable.

    4. Unrelated tool families continued to work normally in the same task, including web search, the GitHub connector, and a separate MCP file tool. Normal model turns also continued. This was not a general tool-runtime or app-server outage.

    5. No thread mutation or retry of a side-effecting thread tool was attempted after the failure.

    This is consistent with the task-scoped handler-registration divergence described here and in #36013, and confirms that the failure family persists on a newer Windows Desktop build and bundled CLI.

    Expected behavior

    If a thread-management tool remains advertised to the active task, its handler should remain registered and callable. If registration is lost, Desktop should either rehydrate the handler atomically or omit the tool and return a structured, recoverable availability error.

    All task identifiers, task titles, project/customer names, local paths, account identifiers, prompt contents, and raw logs are intentionally omitted from this public report.

  13. quiezent commented on Aug 3, 2026

    @quiezent

    Scheduler-impact reproduction on Windows Desktop 26.727.6591.0

    Observed across the 2026-08-03 / 2026-08-04 boundary in Codex Desktop on Windows x64.

    Environment

    • OpenAI.Codex Desktop: 26.727.6591.0
    • matching bundled runtime/CLI: 0.146.0-alpha.9.2
    • long-lived local project tasks
    • no app restart or settings change during the incident

    Operational sequence

    1. A scheduled coordinator fired at its intended time and attempted to wake three independent worker tasks using the official thread-messaging path.
    2. The first target delivery produced no usable acknowledgement. Two bounded follow-up attempts were also unconfirmed.
    3. The coordinator's conservative workflow then stopped before contacting the two unaffected workers and did not rearm itself. All three scheduled work cycles were missed.
    4. In a fresh diagnostic turn, the app still advertised the relevant tools, but direct calls failed with:
      • No handler registered for tool: send_message_to_thread
      • No handler registered for tool: read_thread
      • No handler registered for tool: list_threads
      • No handler registered for tool: automation_update
      • No handler registered for tool: navigate_to_codex_page
    5. Unrelated shell and GitHub connector tools remained functional, so this was not a general app/tool outage.
    6. Because read_thread was also unavailable, delivery could not be reconciled safely. No blind message retry was made.
    7. Because automation_update was unavailable, the coordinator's persisted automation could not be repaired or rearmed through the supported Desktop path. The existing automation remains stranded in its previous state.

    Fallback boundary

    Using the matching CLI with codex exec resume <session-id> <prompt> successfully appended governance-only messages to each task individually. However, an exec-resumed task cannot repair the automation: attempting the dynamic app tool reports that dynamic tool calls are unsupported in exec mode. Directly editing automation TOML was intentionally avoided.

    This adds a concrete operational impact to #28080 and the automation-specific report in #32294: transient handler loss can suppress independent scheduled workers and then remove the only supported recovery/rearm path.

    Expected recovery semantics:

    • re-register all advertised Desktop handlers atomically at scheduled-turn and resume boundaries;
    • fail fast with structured availability rather than hanging or returning an ambiguous acknowledgement;
    • return explicit delivered, not_delivered, unknown, or delivered_but_ack_failed status plus a stable receipt for message sends;
    • isolate one target's delivery failure so it cannot implicitly suppress unrelated targets;
    • keep automation inspection/update available through a supported recovery path.

    No task IDs, local project paths, account identifiers, portfolio data, or raw prompts are included here. No external-system mutation occurred during the reproduction.

  14. hirsrsk commented on Aug 4, 2026

    @hirsrsk

    Interim caller-side mitigation pattern (not a product fix)

    The recent scheduler-impact reproduction suggests a useful interim operating pattern for coordinators and automations while the Desktop handler-lifecycle bug remains unresolved. This is intended to limit duplicate work, indefinite stalls, and unrelated-work suppression; it does not repair the underlying Desktop bridge.

    1. Guard at every turn/resume/scheduled invocation. Before any side-effecting task operation, make one bounded read-only app-tool probe. Distinguish “advertised in the tool catalog” from “handler returned a usable response.”
    2. Use a bounded watchdog. Do not let a Desktop dynamic-tool call block the whole coordinator indefinitely. A timeout means the outcome is unresolved; it does not prove non-delivery.
    3. Treat side-effecting timeout/handler errors as UNKNOWN. Send once with a unique operation key or nonce. Reconcile that exact marker through read_thread before retrying. If the read path is also unavailable, stop and surface uncertainty rather than retrying blindly.
    4. Isolate independent targets. Preserve per-target state so one target's missing acknowledgement does not implicitly mark other targets failed or suppress unrelated work. Continue only operations whose authority and delivery can be independently established.
    5. Revalidate after apparent recovery. A fresh user turn, renderer/window activation, or Desktop restart has restored handlers in some reproductions, but not all. Treat these as recovery attempts, not guarantees, and repeat the read-only guard afterward.
    6. Keep the CLI boundary explicit. codex exec resume <session-id> <prompt> may append a prompt to an existing task, but the resumed CLI turn cannot invoke Desktop-hosted dynamic app tools or repair/manage automations. It is therefore not a complete fallback.
    7. Emit a visible resumable stop. Record the affected target, observed error/timeout, impact, delivery state, resumability, release condition, and next safe action before stopping. Do not leave scheduled state silently stranded.

    Product-side behavior that would make this reliable:

    • atomically register/revalidate advertised handlers at interactive-turn, resume, and automation-start boundaries;
    • add dispatcher-level and per-host deadlines with a structured retryable availability error;
    • return explicit delivered, not_delivered, unknown, or delivered_but_ack_failed status plus a stable receipt for side-effecting calls;
    • correlate request → handler selection → renderer activation/focus → response in diagnostics;
    • isolate one target's delivery failure from independent targets.

    This pattern is deliberately conservative about ambiguous delivery while avoiding the current failure mode where one unresolved call can block an entire coordinator. No task identifiers, local paths, account data, project/customer names, or raw prompts are included.

  15. fibo-blip commented on Aug 4, 2026

    @fibo-blip

    Remote Control connection correlation

    Cross-reference: #36673 reports the same advertised-thread-tool / missing-handler failure while a Desktop task coordinates an existing remote task.

    A Windows Desktop occurrence provides a stronger Remote Control correlation.

    Recorded thread-tool timeline

    Times below are Europe/Lisbon (WEST, UTC+1):

    • 2026-08-03 23:28:56.083 — last recorded successful read_thread.
    • 2026-08-04 00:56:51.551 through 02:41:12.958 — six recorded read_thread attempts returned:
      No handler registered for tool: read_thread
      
    • An authorized Remote Control client had an active connection during the affected period.
    • The Disconnect action shown for that active Remote Control connection was subsequently invoked. This was not removal or deauthorization of the device; it appears to disconnect the active Remote Control session/connection.
    • No read_thread probe was made immediately when Disconnect was invoked.
    • 2026-08-04 10:47:15.497 — the next explicit direct probe invoked read_thread for two known local task IDs.
    • 2026-08-04 10:47:16.707 — both calls returned successfully through the normal Desktop handler.

    The measured recovery window is therefore:

    2026-08-04 02:41:14.146 WEST  (last missing-handler response)
    to
    2026-08-04 10:47:16.707 WEST  (first subsequent successful response)
    

    There was also an earlier observed occurrence with the same sequence: an active Remote Control connection remained established while work resumed on the primary Desktop, local task reads were unavailable, and task access returned after Disconnect was invoked for that Remote Control connection.

    This is a repeated correlation between active Remote Control connection state and local Desktop thread-handler availability. The samples do not establish the exact re-registration moment or whether invoking Disconnect is the direct cause, because there was no continuous probe between disconnect and recovery. However, Remote Control host/controller routing should be included explicitly in diagnosis rather than treating this only as a generic per-turn handler-loss issue.

    Useful diagnostics would include:

    • selected local/remote host and renderer/client for every advertised thread tool;
    • active Remote Control connection/session state and generation;
    • handler registration changes when a Remote Control connection is established or Disconnect is invoked;
    • whether local handlers are shadowed, rebound, or left stale while another authorized controller has an active connection;
    • a structured error distinguishing target unavailable, remote host unavailable, routing conflict, and handler unregistered.
  16. quiezent commented on Aug 4, 2026

    @quiezent

    Android Remote reproduction with confirmed non-delivery

    A later controlled reproduction on 2026-08-04 narrows the Remote source and delivery outcome.

    This occurred while ChatGPT Android Remote controlled an existing local Desktop Scheduler task. The task was not created from mobile.

    Sanitized UTC timeline:

    • 14:25:33 — in an earlier Android-controlled turn, advertised automation_update returned:
      No handler registered for tool: automation_update
    • 14:30:38 — a new Android Remote user turn reached the existing local Scheduler task.
    • 14:30:51 — tool lookup exposed send_message_to_thread.
    • 14:31:12 — exactly one send was attempted to worker A.
    • The call returned:
      No handler registered for tool: send_message_to_thread
    • No retry was made, and workers B and C were not contacted.

    Delivery was reconciled afterward against the exact worker rollout records. The send's unique prompt marker was absent from worker A's rollout at the audit cutoff. Thus this particular handler error represented true non-delivery, rather than the delivered-but-acknowledgement-failed behavior reported in #29886.

    Environment:

    • OpenAI.Codex Desktop: 26.727.6591.0
    • matching bundled runtime/CLI: 0.146.0-alpha.9.2
    • Windows x64
    • mobile controller: ChatGPT/Codex Remote on Android

    This adds an Android Remote control-path boundary to the scheduled-coordinator reproduction already reported here:

    • the tool remained advertised;
    • the controlling task was an existing local task;
    • both messaging and automation handlers were unavailable across adjacent Remote turns;
    • one failed target suppressed independent scheduled workers under conservative fail-closed logic.

    The important safety conclusion is that the same caller-visible handler error has now been observed with both outcomes:

    1. delivery occurred despite the error; and
    2. delivery did not occur.

    Accordingly, callers cannot safely retry or mark failure from this error alone. Side-effecting thread tools need a stable operation/message ID and an explicit result such as delivered, not_delivered, unknown, or delivered_but_ack_failed.

    Handler registration should also be revalidated atomically at Android Remote turn, task-resume, and scheduled-automation boundaries, and one target's unresolved result should not suppress unrelated targets.

    Related Android-specific report: #32553. Automation-specific form: #32294. Scheduled-run overlap: #35030.

    No task IDs, portfolio information, raw prompts, local paths, or account identifiers are included.

  17. fibo-blip commented on Aug 4, 2026

    @fibo-blip

    Controlled before/after Disconnect reproduction

    A new A/B check on 2026-08-05 narrows the recovery boundary reported above.

    Codex Desktop remained running throughout; there was no application restart.

    Times below are Europe/Lisbon (WEST, UTC+1):

    • While a Remote Control connection was active:
      • 00:16:22.359 — read_thread returned No handler registered for tool: read_thread.
      • wait_threads also returned No handler registered for tool: wait_threads.
    • The local rollout/session record remained readable during the failure, so stored thread history was intact.
    • After invoking Disconnect for the current Remote Control connection — not removing or deauthorizing the device:
      • 00:16:48.318 — read_thread succeeded.
      • 00:16:55.281 — wait_threads succeeded.

    The observed handler transition occurred within 26 seconds between the failed and successful read_thread probes, without an app restart or changes to the task/session data.

    This is stronger A/B evidence for the same boundary: an active Remote Control connection coincided with unavailable local Desktop thread handlers, and disconnecting that current connection was immediately followed by successful handler dispatch. It does not by itself prove the internal root cause, but it strongly points to Remote Control connection lifecycle or handler routing rather than rollout size or stored-session corruption.

  18. ginishuh commented on Aug 5, 2026

    @ginishuh

    Controlled cross-surface resume reproduction: an existing coordinator thread remains poisoned across Mobile, Desktop, and CLI

    I reproduced a stronger persistence boundary on 2026-08-05. This was an existing long-running project coordinator thread that had previously depended on the official Desktop thread tools.

    Environment

    • Windows 11 x64 host
    • Windows Codex Desktop, updated immediately before this reproduction (exact package version was not available from the WSL session)
    • WSL2 Ubuntu host: codex-cli 0.146.0
    • ChatGPT mobile remote as the first affected surface
    • Same persisted thread resumed across all surfaces; repository contents were not required to reproduce the failure

    Reproduction timeline

    1. Resume the existing coordinator thread from ChatGPT mobile remote.

    2. The model still receives the official codex_app__* thread-tool declarations.

    3. Calls fail with missing-handler errors, including:

      No handler registered for tool: create_thread
      No handler registered for tool: list_threads
      No handler registered for tool: list_projects
      
    4. A failed create_thread attempt was rendered in Windows Desktop as a successful-looking "chat created" tool card, while the persisted assistant/tool result immediately below still contained No handler registered for tool: create_thread. Because reconciliation tools were also unavailable, the caller could not safely determine whether the mutation happened and could not safely retry.

    5. Fully quit and restart Codex Desktop, then resume the same thread in Desktop. Read-only calls still fail:

      No handler registered for tool: list_projects
      No handler registered for tool: read_thread
      
    6. Quit Desktop and resume the same persisted thread from WSL Codex CLI. The same calls fail instead with:

      dynamic tool request failed
      
    7. Open Desktop while the CLI-owned resume is still active. Calls retain the CLI-side dynamic tool request failed result.

    8. Exit the CLI completely, resume the thread again from Windows Desktop, and start a fresh user turn.

    9. The errors switch back to the Desktop-specific missing-handler form:

      No handler registered for tool: list_projects
      No handler registered for tool: read_thread
      
    10. Repeat the Desktop resume and read-only calls. The handler does not recover.

    This distinguishes surface switching from recovery: the error mode follows the active surface, but the existing thread never rehydrates a working Desktop task-tool binding.

    Operational impact

    The affected coordinator thread can continue ordinary model turns and shell/GitHub work, but it can no longer safely:

    • discover saved projects or existing tasks;
    • read or wait for delegated tasks;
    • send follow-up messages to existing tasks;
    • create a successor task;
    • reconcile whether a mutating task-tool call was delivered.

    The underlying existing tasks are not necessarily lost and can still be opened manually in the UI. The broken part is cross-thread coordination from the resumed coordinator. The practical recovery is to create a brand-new Windows Desktop coordinator task and manually transfer context, which defeats persistent-thread resume.

    Expected behavior

    On every thread/resume or remote/CLI/Desktop surface transition:

    1. Re-negotiate client-specific dynamic tool capabilities before accepting a user turn.
    2. Register exactly one authoritative handler owner for each mutating dynamic tool.
    3. Do not advertise a tool when the active surface has no executable handler.
    4. Do not render a success-state tool card until the authoritative tool result confirms success.
    5. Return explicit delivered, not_delivered, or unknown semantics for mutating thread tools so callers never retry blindly.
    6. Provide a supported way to rehydrate task-tool bindings for an existing thread without abandoning its context.

    Likely related boundaries

    This reproduction appears to connect those symptoms: dynamic tool definitions persist with the thread, executable handlers remain surface/client-specific, and resume does not reliably reconcile the two.

    No private prompts, project paths, credentials, or thread IDs are included.

  19. rayhlw commented on Aug 5, 2026

    @rayhlw

    macOS + iPhone Remote Control reproduction: surface switch changes route and drops wait_threads handler

    I can reproduce a surface-switch-specific variant on the current macOS build.

    Environment

    • ChatGPT Desktop: 26.730.61639 (build 6234)
    • Bundled CLI: codex-cli 0.147.0-alpha.1.2
    • macOS 27.0 (26A5388g)
    • Mobile control surface: ChatGPT on iPhone, Remote
    • Same signed-in account, same Mac host, same existing visible coordinator and worker threads

    Minimal sequence

    1. Keep one coordinator thread and one visible worker thread open on the Mac.
    2. From computer Remote Control, list_threads reports both threads on a remote-control:* host route.
    3. Open and continue the same coordinator from iPhone Remote.
    4. The current project/tool route resolves through slingshot:*, while thread listings may still resolve the same identities through remote-control:*.
    5. Call codex_app.wait_threads once for the known worker, including an immediate timeoutMs: 0 snapshot.
    6. It fails immediately with:
    No handler registered for tool: codex_app.wait_threads
    
    1. A single send_message_to_thread call to an existing visible diagnostic worker may return:
    Something went wrong while running this tool.
    

    However, the target thread's update timestamp changes, it runs to completion, and its worker-to-coordinator send_message_to_thread message is delivered successfully. This is a confirmed delivered-side-effect / lost-ack case.
    8. Switching control back to the computer changes the observed route again without restarting either app. The worker itself never loses state.

    What this narrows down

    • This is not a dead worker, lost project, or general app-server outage.
    • Handler availability diverges from the advertised tool catalog after a mobile/desktop control-surface switch.
    • The same thread identity can be associated with remote-control:* and slingshot:* routing during the failure window.
    • wait_threads can be unavailable while ordinary visible-task execution and worker-to-coordinator delivery still work.
    • Retrying a side-effecting send is unsafe: duplicate terminal reports can result when the original delivery succeeded but its acknowledgement was lost.

    Expected behavior

    • Rebind or re-register advertised thread-tool handlers when the active control surface or route changes.
    • Preserve one authoritative thread/host route across mobile and desktop resume.
    • Return explicit delivered, not_delivered, unknown, or delivered_but_ack_failed status plus a stable operation/message ID.
    • Make wait_threads resolve the live thread identity independently of whether the coordinator was most recently resumed from mobile or desktop.
    • Do not require an app/computer restart or force the user to stay on one control surface.

    Operational workaround validated locally

    Use a single idempotency key per worker turn; send exactly one native completion/material-blocker message to the coordinator; never retry on an acknowledgement error; treat wait_threads as optional monitoring and independently verify worker results. This keeps visible tasks usable across phone/computer switches but does not fix the underlying handler-registration bug.

    No project data or full session transcript is included here. I can provide a narrowly sanitized log window or feedback session ID if a maintainer requests it.

  20. rayhlw commented on Aug 5, 2026

    @rayhlw

    Follow-up: the same surface switch can also change the worker model and reasoning effort

    The same macOS/iPhone reproduction exposed a second route-bound state leak in one existing visible worker thread.

    Local rollout turn_context records show this exact sequence:

    • The worker was created as gpt-5.6-luna / xhigh and remained on that pair across its normal turns.
    • A continuation delivered while the coordinator was resumed through the mobile slingshot:* route started the worker's next turn as gpt-5.6-sol / medium.
    • The coordinator call omitted model and thinking, which the tool contract says should keep the target thread's current settings.
    • After control returned to the computer remote-control:* route, another continuation to the same worker, also without model/thinking overrides, started as gpt-5.6-luna / xhigh again.
    • The worker UI visibly rendered: “Model changed from GPT-5.6 Sol to GPT-5.6 Luna.”

    This indicates that control-surface route drift can affect not only handler registration and acknowledgements but also model/effort continuity for an existing task. The target thread identity and worktree did not change.

    Expected behavior: omitting model/thinking on send_message_to_thread should preserve the target thread's bound settings regardless of whether the coordinator is currently routed through mobile or desktop. If the system intentionally applies a caller-side override, the API should expose that resolved routing before execution rather than silently changing the worker.

    Current safety workaround: coordinators must explicitly repeat the worker's model and effort on every continuation/correction. This avoids silent route-model drift but should not be necessary under the documented preservation behavior.

  21. quiezent commented on Aug 6, 2026

    @quiezent

    Additional Windows Desktop reproduction after a full process-tree restart and Store update (2026-08-06):

    Environment

    • Windows 11
    • Desktop MSIX updated from 26.727.6591.0 to 26.730.8199.0
    • Desktop internal client after restart: 26.730.61639
    • Compatible user-local CLI: codex-cli 0.147.0-alpha.1.2

    Restart/update result
    The old Desktop process tree was fully terminated and the signed Store package relaunched. The update completed successfully and a fresh app-server started. The defect persisted.

    After restart, the deferred tool catalog continued to advertise full schemas for:

    • read_thread
    • list_threads
    • send_message_to_thread
    • navigate_to_codex_page
    • automation_update

    But invocation immediately returned:
    No handler registered for tool: <name>

    This reproduced in two existing Desktop threads. In the scheduler/coordinator thread, three independent manager sends each failed before recipient lookup; controlled reconciliation confirmed 0/3 native deliveries. Desktop logs explicitly showed thread_tools enabled after startup, so the observable failure is a divergence between the advertised dynamic-tool catalog and the live client handler registry.

    There was no positive Remote Control subscriber evidence in the local logs: remote host/control inventory remained zero during the reproduction.

    Limited workaround and boundary
    A current user-local CLI binary could resume each recipient session. Three bounded A2 continuations completed with matching acknowledgements, confirming the recipient sessions themselves were healthy. However this is not a product fix:

    • codex exec resume cannot service Desktop dynamic tools and reports dynamic tool calls are not supported in exec mode.
    • Therefore it can continue a task that only needs CLI/shell capabilities, but it cannot replace automation_update or native inter-thread messaging generally.
    • On Windows, Get-Command codex resolved the packaged Program Files\WindowsApps\...\codex.exe, which failed with Access is denied; only the current user-local hashed CLI was executable.

    No release/restart recovery was observed on 26.730.8199.0. This remains consistent with a handler-registration/lifecycle defect rather than a recipient authorization or prompt problem.

  22. quiezent commented on Aug 7, 2026

    @quiezent

    Scheduler dead-end confirmed on Windows Desktop 26.730.8199.0 (2026-08-07)

    A scheduled-task coordinator reproduced the combined failure mode after the full restart/update described above.

    1. In the Desktop task surface, read_thread, send_message_to_thread, and automation_update remained advertised but returned No handler registered.
    2. The same existing scheduler task was then continued with the compatible user-local CLI codex-cli 0.147.0-alpha.1.2.
    3. In exec-resume mode it attempted only the supported automation view/update calls. Both failed immediately, with app-server logs reporting:
    dynamic tool calls are not supported in exec mode
    

    and the task received only:

    dynamic tool request failed
    

    This establishes a complete recovery dead-end:

    • Desktop continuation cannot call the advertised handler because it is unregistered.
    • CLI continuation can keep the task/session alive, but is intentionally unable to service dynamic Desktop tools.
    • Therefore an existing active heartbeat cannot be safely viewed, repaired, or rearmed through either supported path.
    • Raw automation-file edits and OS schedulers were deliberately not used.

    Operational consequence in this reproduction: the persisted heartbeat retained a stale recurrence, and a time-sensitive next wake could not be armed despite the target thread and normal CLI execution remaining healthy. No duplicate automation was created and no messages were sent.

    A useful product-level recovery would be either (a) deterministic handler re-registration at local/remote/CLI-resume boundaries, or (b) a supported app-server/CLI automation management command that returns explicit applied/not-applied state when the Desktop handler is unavailable.

  23. ginishuh commented on Aug 7, 2026

    @ginishuh

    Post-update Android Remote matrix: no permanent poison, but tool-specific handler loss and false-negative mutations remain

    I reran a controlled task-management matrix on 2026-08-07 after the latest available app update, from ChatGPT mobile Remote against the same existing coordinator that I previously reported in this comment.

    This is a materially improved recovery boundary: the coordinator is no longer permanently unable to manage other tasks. However, advertised-handler divergence still occurs within one user turn, and some mutating calls can apply their side effect while returning No handler registered.

    Environment and method

    • Windows 11 Desktop host with the app updated immediately before this check
    • ChatGPT mobile Remote as the control surface
    • WSL remote project host; persisted session metadata reports codex-cli 0.147.0
    • The exact updated Desktop/mobile package versions were not exposed inside the remote task
    • The live dynamic-tool catalog advertised all 14 available codex_app functions
    • Every mutating probe used a disposable task and a unique marker
    • A mutating call was not blindly retried after a handler error; delivery was reconciled through read_thread or local session metadata

    Results

    Tool Result
    list_projects FAIL twice in the same user turn: No handler registered for tool: list_projects
    list_threads FAIL twice in the same user turn: No handler registered for tool: list_threads
    create_thread PASS in the controlled matrix with an explicit thread ID; the task completed normally
    read_thread PASS repeatedly, including exact marker/response reconciliation
    send_message_to_thread PASS; a unique follow-up marker was delivered and acknowledged
    wait_threads MIXED: succeeded against an existing idle task early in the turn, then returned No handler registered for tool: wait_threads immediately after the disposable task was created
    set_thread_title PASS, confirmed by subsequent read_thread and session metadata
    set_thread_pinned PASS for both pin and unpin
    set_thread_archived PASS for archive, unarchive, and final cleanup archive
    fork_thread FALSE NEGATIVE: returned No handler registered for tool: fork_thread, but a fork was actually created with the completed source history
    handoff_thread PASS from checkout to a disposable worktree and back
    get_handoff_status PASS for both handoffs, with every step reported complete
    read_thread_terminal Handler PASS; returned the structured expected result that no app terminal was attached
    open_in_codex Handler PASS; returned queued for the mobile-controlled/hidden panel

    Additional false-negative creation evidence from the same updated session

    Immediately before the controlled matrix, three create_thread calls each returned:

    No handler registered for tool: create_thread
    

    All three tasks were nevertheless created and visible in the mobile UI. The retries therefore produced three duplicates. They were later identified from session metadata and archived successfully. This confirms that the caller-visible handler error still cannot be treated as not_delivered for create_thread.

    What changed from the earlier reproduction

    The previous affected coordinator remained poisoned across Mobile, Desktop, and CLI resumes and could not recover working task tools. After the update, the same practical workflow can now create, read, message, wait for, rename, pin, archive, fork, and hand off tasks. A fresh user turn also restored functions that had failed earlier.

    The remaining defect is narrower but still unsafe:

    1. handler availability differs by tool inside one turn;
    2. list_projects and list_threads can remain unavailable while other task tools work;
    3. wait_threads can transition from working to missing-handler during the same turn;
    4. mutating create_thread and fork_thread can return a handler error after the side effect occurred;
    5. blind retries can create duplicate tasks.

    This still needs an explicit operation result such as delivered, not_delivered, unknown, or delivered_but_ack_failed, plus a stable operation/message ID. Advertised handlers should also be revalidated atomically at every mobile Remote turn/resume boundary and before dispatch.

    All disposable test tasks were archived, the temporary handoff worktree was removed after a clean-state check, and the repository checkout remained clean. No private task IDs, prompts, project names, or local paths are included here.

  24. ginishuh commented on Aug 7, 2026

    @ginishuh

    Post-update mobile-created fresh root: all task-management tools missing

    I ran this check on 2026-08-07 from a brand-new root task created directly in the ChatGPT mobile Remote UI immediately after the mobile app update. This was not a resume of an existing session. The operator subsequently confirmed that the thread under test itself—not merely its control surface—was created from mobile Remote.

    Environment visible inside the remote task:

    • Time zone: Asia/Seoul
    • Codex CLI / app-server: 0.147.0
    • Desktop and mobile app package versions: not exposed to the remote task
    • Persisted session metadata: source=vscode, originator=Codex Desktop, and thread_source=null

    The live tool registry exposed 0 codex_app__* tools. In particular, none of the 14 task-management functions from the earlier post-update matrix were available:

    list_projects, list_threads, create_thread, read_thread, wait_threads, send_message_to_thread, set_thread_title, set_thread_pinned, set_thread_archived, fork_thread, handoff_thread, get_handoff_status, read_thread_terminal, and open_in_codex.

    I made one direct open_in_codex invocation attempt. It could not reach handler dispatch because the callable was absent from the registry (tools[toolName] is not a function). This is therefore not a No handler registered result and does not establish a mutation false negative.

    The same thread was then continued across two subsequent fresh user turns. On both turns, the live registry still exposed 0 task-management tools. A direct create_thread invocation was attempted once in each of those explicitly requested turns; both attempts failed before handler dispatch with tools[toolName] is not a function. Exact-title readback from the local thread index returned no matching child, so neither attempt created the disposable task.

    Because no task-management readback tool was available, the remaining lifecycle matrix could not run safely. No task, fork, handoff, worktree, file, branch, commit, PR, or issue-state mutation was created; the original checkout remained clean.

    This differs from the earlier post-update matrix, where all 14 functions were advertised but some handlers failed or returned false negatives. The fresh-root result is more directly related to #34526: it appears to be a stronger reduced-profile case, with the entire task-management surface omitted rather than only selected capabilities. It also means the fresh-root recovery boundary for #28080 cannot be validated from this task, because no handler can be invoked at all.

    The persistence across fresh user turns makes a transient single-turn catalog failure less likely. The mismatch between the confirmed mobile creation path and the persisted source=vscode / originator=Codex Desktop / null thread_source metadata may be useful for locating the capability-profile routing boundary.

    Expected behavior: a mobile-created fresh Remote root should receive the same supported task-management profile as an equivalent full-profile task, or the product should explicitly disclose and diagnose the reduced profile.

  25. copelandtucker0c5pg7p-droid commented on Aug 9, 2026

    @copelandtucker0c5pg7p-droid

    Additional sanitized reproduction and recovery evidence from Windows 11 x64:

    • Codex Desktop: 26.803.5235.0
    • Bundled CLI observed: 0.147.0-alpha.6.5
    • Affected tools in this session: list_projects and list_threads
    • Exact symptom: intermittent No handler registered for tool: <tool> while read_thread and wait_threads remained callable.
    • The failing cold calls returned the handler error after roughly 0.9–1.0 s, while paired Desktop logs later recorded a successful response for the same operation about 3.5–8.2 s after dispatch. Immediate retries could temporarily warm the handler.
    • The signed Store package reported healthy status, the relevant SQLite databases passed integrity checks, and no newer Store build was available at the time of testing.

    A minimal runtime-only recovery was tested: restart only the existing codex-code-mode-host.exe child process and allow the current app-server to spawn a replacement. Desktop and app-server were not restarted, and no state/cache/database files were modified.

    Initial post-restart checks:

    • first list_projects / list_threads calls both succeeded (about 70 ms);
    • after 35 s idle, both succeeded (about 1.8 s / 2.7 s);
    • after 70 s idle, both succeeded (about 1.5 s / 2.3 s);
    • native send/wait/read against an existing thread completed end-to-end without creating a replacement thread.

    Correction after a longer idle interval: after several additional minutes, both list tools again returned No handler registered in about 0.7 s while the replacement host process was still alive. Restarting only the code-mode host is therefore a temporary recovery, not a durable fix.

    This remains consistent with a stale code-mode-host / Desktop dynamic-handler bridge lifecycle rather than missing tool schemas or damaged thread state. A supported auto-reinitialize/retry path when the host-side handler bridge becomes stale would avoid requiring process restarts.

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 interfacesbugSomething isn't workingtool-callsIssues related to tool callingwindows-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