Codex Desktop intermittently exposes thread tools without registered handlers
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_threadsread_threadsend_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(build25F71) - Architecture: Apple Silicon /
arm64 - Observed: 2026-08-02 through 2026-08-03
Reproduction
- Open or resume a long-lived Codex Desktop thread that coordinates another existing remote task.
- Inspect/search the available tool surface.
- Confirm
codex_app.list_threads,codex_app.read_thread, andcodex_app.send_message_to_threadare present with complete schemas. - Invoke one of those tools.
- Intermittently observe:
``text`
No handler registered for tool: list_threads
read_thread
or the equivalent error for / send_message_to_thread`.
- Retry later in the same local thread. A read-only tool such as
list_threadsmay 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_threadmust 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_appthread-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.
4 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Windows same-process reproduction with concurrent saved tasks
I captured a new Windows reproduction that narrows the lifecycle boundary considerably.
Environment
1904526.727.6591.0Codex Desktop 26.727.513510.146.0codex.exeprocess started at2026-08-04 16:45:37 UTCand 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 returnedcodex_appnamespace explicitly containedlist_threadswith its full schema.22:38:09.615— task A invokedlist_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 exposingread_thread.22:39:13.752— task B invokedread_thread.22:39:14.167— after 415 ms:No handler registered for tool: read_thread.22:39:36.065— task B invokedlist_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 retriedlist_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_threadssuccess/failure alternation across July 27, July 29, August 1, August 3, and August 4.Context-size control
At the principal failure:
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:
delivered,not_delivered, orunknownsemantics;list_threadsandread_threadwhile switching the active task.No task IDs, local paths, usernames, prompts, project data, credentials, or complete logs are included.
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
26.727.6591.0(OpenAI.Codex_26.727.6591.0_x64__2p2nqsd0c76g0)10.0.26200, build262002026-08-05 16:05 UTC(2026-08-06 00:05 Asia/Kuala_Lumpur)Reproduction
codex_app__send_message_to_threadwith its complete callable schema, includinghostId,threadId, andprompt.hostId: "local"and a known existing destination thread.``
text
``No handler registered for tool: send_message_to_thread
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_threadsorread_threadcall was required: discovery advertisedsend_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, orunknownresult (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.Current control: core thread path succeeds, but one advertised
list_threadsfield is rejectedA 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
list_threadssucceeded and discovered the target task by title.read_threadsucceeded.list_threadstool description advertised an optionalqueryfield, but:``
text
``list_threads({query: ...})
-> Unrecognized key: query
send_message_to_threadwrapper failed before dispatch with:``
text
``SyntaxError: Unexpected string
wait_threadsreturned the target task's exact response in approximately 4.4 seconds.Interpretation
queryresult is a direct schema/implementation mismatch: one task receives a published schema that the invocation validator rejects.SyntaxErroris 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.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:
list_threads.query;No thread IDs, task titles, message bodies, project paths, host identifiers, usernames, or private task content are included.