Codex Desktop intermittently exposes thread tools without registered handlers

Open 💬 4 comments Opened Aug 3, 2026 by futurenowlabs
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

Summary

Codex Desktop intermittently exposes the codex_app thread-management tools to the model, including their complete schemas, but invocation fails with:

No handler registered for tool: <tool_name>

The failure has affected at least:

  • list_threads
  • read_thread
  • send_message_to_thread

The same tool can fail and later succeed in the same resumed Desktop thread. This appears to be a Desktop/app-server dynamic-tool handler registration or routing problem rather than the target thread being absent.

Environment

  • Codex Desktop version: 26.727.51351
  • Bundle build: 6119
  • Bundle identifier: com.openai.codex
  • macOS: 26.5 (build 25F71)
  • Architecture: Apple Silicon / arm64
  • Observed: 2026-08-02 through 2026-08-03

Reproduction

  1. Open or resume a long-lived Codex Desktop thread that coordinates another existing remote task.
  2. Inspect/search the available tool surface.
  3. Confirm codex_app.list_threads, codex_app.read_thread, and codex_app.send_message_to_thread are present with complete schemas.
  4. Invoke one of those tools.
  5. Intermittently observe:

``text
No handler registered for tool: list_threads
`
or the equivalent error for
read_thread / send_message_to_thread`.

  1. Retry later in the same local thread. A read-only tool such as list_threads may succeed and return the existing remote task, then fail again on a subsequent invocation.

The issue was observed around resumed-thread use, heartbeat wakeups, and context transitions, but a single exact trigger has not yet been isolated.

Expected behavior

  • Any thread-management tool exposed to the model must have a registered callable handler for that turn.
  • If the target thread or remote host is unavailable, return a specific target/host/session error rather than a missing-handler error.
  • Mutating calls such as send_message_to_thread must have an unambiguous completion result so callers can safely decide whether retrying is allowed.

Actual behavior

  • Tool schema discovery succeeds while invocation reports that no handler is registered.
  • Registration appears intermittent within one local thread.
  • The target remote task can still be listed as existing and active between failures.
  • Other connector tools continue to work, so the failure appears isolated to the Desktop thread-management bridge.

Safety / exactly-once concern

send_message_to_thread can return the missing-handler error while the target task later appears active or has a newer update timestamp. It is therefore unclear whether the write definitely did not happen.

This creates a duplicate-action risk: blindly retrying a deployment, rollback, or other operational instruction could submit it twice. The API should return a definitive result or an idempotency/operation identifier.

Related issues

  • #25990 — older resumed Desktop threads can miss newly available tools
  • #29223 — fresh sessions can lose the codex_app thread-management surface

This report differs because the affected tools are present in the advertised tool surface, but their handlers intermittently cannot be invoked.

Additional information

No private thread IDs, repository names, host identifiers, prompts, message bodies, credentials, or runtime contents are included in this report.

View original on GitHub ↗

4 Comments

github-actions[bot] contributor · 25 days ago

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

  • #36013
  • #36404
  • #35894

Powered by Codex Action

ESKehler · 23 days ago

Windows same-process reproduction with concurrent saved tasks

I captured a new Windows reproduction that narrows the lifecycle boundary considerably.

Environment
  • Windows 10 Home x64, build 19045
  • Codex Desktop package: 26.727.6591.0
  • Desktop app-server requests identify the client as Codex Desktop 26.727.51351
  • Bundled runtime model-cache version: 0.146.0
  • 15.9 GiB RAM; Intel Core i7-7700HQ
  • The app and codex.exe process started at 2026-08-04 16:45:37 UTC and remained running throughout the principal reproduction.
Principal timeline (UTC)

Three saved tasks overlapped:

  • 22:34:19.779 — task C started and remained active.
  • 22:37:48.426 — task A started.
  • 22:38:05.837 — task A completed tool discovery; the returned codex_app namespace explicitly contained list_threads with its full schema.
  • 22:38:09.615 — task A invoked list_threads.
  • 22:38:10.052 — after 437 ms: No handler registered for tool: list_threads.
  • 22:39:02.312 — task B started.
  • 22:39:10.799 — task B completed discovery exposing read_thread.
  • 22:39:13.752 — task B invoked read_thread.
  • 22:39:14.167 — after 415 ms: No handler registered for tool: read_thread.
  • 22:39:36.065 — task B invoked list_threads.
  • 22:39:36.572 — the same missing-handler error returned.
  • 22:42:13.155 — task A completed normally; the model/app-server was not generally dead.
  • 22:59:20.980 — task B repeated tool discovery successfully.
  • 22:59:23.982 — task B immediately retried list_threads.
  • 22:59:24.417 — missing-handler failure returned again.

This shows that discovery and invocation disagreed within 3–4 seconds, the condition crossed task boundaries, it persisted for more than 21 minutes, and rediscovery did not repair registration. Unrelated shell and GitHub connector calls continued working.

Same-process success/loss/recovery evidence

The same saved coordinator task recorded this sequence earlier on August 4:

| UTC | Tool | Result |
| --- | --- | --- |
| 14:52:16.545 | read_thread | success |
| 14:52:22.074 | read_thread | missing handler, only 5.5 seconds later |
| 15:18:30.267 | list_threads | success |
| 15:22:52.457 | read_thread | missing handler |
| 15:26:29.251 | read_thread | success without restarting |
| 15:44:02.244 | send_message_to_thread | missing handler |
| 15:56:06.944 | send_message_to_thread | missing handler |
| 16:49:22.777 / 16:49:48.629 | read_thread | success after restart |
| 17:07:14.904 | list_threads | success in the same process that later failed |
| 22:39:14.167 | read_thread | missing handler |
| 22:39:36.572 | list_threads | missing handler |

This demonstrates both loss and recovery without a restart, plus only temporary recovery after restart. A second saved task has repeated list_threads success/failure alternation across July 27, July 29, August 1, August 3, and August 4.

Context-size control

At the principal failure:

  • task A was at approximately 70% of a 258,400-token context window;
  • task B was at approximately 35%;
  • concurrent task C was at approximately 42%.

Long-lived tasks and concurrent hydration may increase exposure, but a near-full context is not required: task B failed at only 35%.

Evidence source and likely boundary

Exact calls/results came from durable per-task rollout records. The matching rows in the live SQLite log were visible immediately after the incident but were pruned during the investigation, so complete raw logs are not durable enough for delayed reporting.

The strongest inference is divergence between the advertised deferred-tool catalog and the live Desktop handler registry, potentially exposed by concurrent task activation: discovery returns one catalog generation, invocation finds no corresponding handler, another task sees the same missing registry shortly afterward, and rediscovery returns the schema again without repairing it.

Useful fixes/diagnostics would be:

  • make schema publication and handler registration atomic per turn/client generation;
  • log a handler-generation ID at discovery, dispatch, renderer selection, and response;
  • revalidate/rebind handlers at task start/resume, context restoration, Remote Control connection changes, and concurrent-turn activation;
  • omit tools whose handler is absent, or return a structured recoverable availability error;
  • give mutating calls a stable operation ID plus delivered, not_delivered, or unknown semantics;
  • add a stress test with three concurrent saved tasks repeatedly discovering/invoking list_threads and read_thread while switching the active task.

No task IDs, local paths, usernames, prompts, project data, credentials, or complete logs are included.

quiezent · 22 days ago

Additional Windows heartbeat reproduction (send_message_to_thread)

I reproduced the same advertised-tool / missing-handler mismatch in a long-lived scheduled-task coordinator.

Environment
  • Codex Desktop package: 26.727.6591.0 (OpenAI.Codex_26.727.6591.0_x64__2p2nqsd0c76g0)
  • Windows 11 Pro x64, version 10.0.26200, build 26200
  • Observed at approximately 2026-08-05 16:05 UTC (2026-08-06 00:05 Asia/Kuala_Lumpur)
  • The affected task is a long-lived heartbeat/scheduler coordinator that sends neutral status notices to existing saved tasks.
Reproduction
  1. A scheduled checkpoint woke the existing coordinator task.
  2. Top-level tool discovery returned codex_app__send_message_to_thread with its complete callable schema, including hostId, threadId, and prompt.
  3. The coordinator immediately invoked it with hostId: "local" and a known existing destination thread.
  4. The call returned in about 0.5 seconds with:

``text
No handler registered for tool: send_message_to_thread
``

  1. Web/time and GitHub connector calls continued to work, so the task and tool system were not generally unavailable.

The intended checkpoint had three existing recipient tasks and used sequential delivery. I stopped after the first handler failure to avoid duplicate or ambiguous delivery. Result: 0/3 deliveries confirmed.

This adds a scheduler/heartbeat-specific Windows reproduction where no list_threads or read_thread call was required: discovery advertised send_message_to_thread, but its Desktop-side handler was absent at dispatch. The failure prevents reliable scheduled cross-thread notifications.

For mutating sends, a definitive delivered, not_delivered, or unknown result (ideally with an operation/idempotency ID) would make safe retry behavior possible. No task IDs, message bodies, project data, local paths, or credentials are included here.

ESKehler · 1 day ago

Current control: core thread path succeeds, but one advertised list_threads field is rejected

A fresh end-to-end control on Windows produced a useful mixed result. Computer Use was disabled and absent from the active skill catalog throughout.

Results
  1. Unfiltered list_threads succeeded and discovered the target task by title.
  2. read_thread succeeded.
  3. In that same source task, the live list_threads tool description advertised an optional query field, but:

``text
list_threads({query: ...})
-> Unrecognized key: query
``

  1. A first inline send_message_to_thread wrapper failed before dispatch with:

``text
SyntaxError: Unexpected string
``

  1. Repeating the same send using a separately constructed arguments object succeeded.
  2. wait_threads returned the target task's exact response in approximately 4.4 seconds.
  3. The visibly selected Codex task never changed during discovery, read, send, or wait.
Interpretation
  • Thread discovery/read/send/wait are independent of Computer Use and can work end-to-end while it is disabled.
  • The query result is a direct schema/implementation mismatch: one task receives a published schema that the invocation validator rejects.
  • The one wrapper SyntaxError is not established as a thread-tool handler bug because it occurred before dispatch and the equivalent constructed-args call succeeded. It may be caller-side wrapper/string construction; it is included only to preserve the observed boundary.
  • Background thread coordination does not require the target task to become visibly selected.

This complements the missing-handler cases in this issue: even when handlers are registered and the core route works, different tasks can receive incompatible argument schemas.

Useful fixes/tests:

  • generate publication and validation from one canonical schema version;
  • include a schema/catalog generation ID in discovery and validation errors;
  • add a test that invokes every advertised optional field, including list_threads.query;
  • keep send results explicit enough to distinguish pre-dispatch failure from delivered/unknown.

No thread IDs, task titles, message bodies, project paths, host identifiers, usernames, or private task content are included.