### What version of the Codex App are you using?
- ChatGPT/Codex desktop app: `…26.727.40816`
- Bundle build: `6067`
- Bundled Codex CLI: `0.146.0-alpha.9.2`
- Previous desktop release observed in local logs: `26.721.81911`
### What subscription do you have?
Not provided.
### What platform is your computer?
macOS on Apple silicon.
### What issue are you seeing?
Realtime Voice can see Codex task and project metadata but cannot reliably create or coordinate Codex tasks. A harmless projectless task was created successfully from Voice, completed, and reported back. Immediately afterward, one advertised task tool had no registered handler. Roughly 92 seconds after the child completed, subsequent live task operations began failing and the same host was reported as `thread_list_unavailable`.
The affected operations include:
- `create_thread`
- `read_thread`
- `wait_threads`
- `send_message_to_thread`
- `fork_thread`
- `read_thread_terminal`
Most calls return only:
```text
Something went wrong while running this tool.
```
Two advertised tools returned:
```text
No handler registered for tool: codex_app.wait_threads
No handler registered for tool: codex_app.read_thread_terminal
```
Thread listing can still return cached task rows while also reporting the current host as unavailable:
```text
reason: thread_list_unavailable
```
Manual task creation through the desktop app remains healthy. Selecting **New Task** and sending a short prompt produces a normal response in approximately ten seconds. This appears specific to the Realtime Voice-to-Codex task-tool bridge rather than a general task-runtime failure.
The routing-race analysis later in this report is an inference from public source code and symptom correlation. It is not a confirmed root cause and is intentionally separated from the directly observed evidence.
### What steps can reproduce the bug?
1. Start a new Realtime Voice conversation in the ChatGPT desktop app.
2. Ask Voice to create one harmless projectless Codex task that performs no mutations and reports back when complete.
3. Observe that the first `create_thread` may succeed and the child task can complete normally.
4. Ask Voice to wait for or inspect that task.
5. Observe that `wait_threads` may return `No handler registered`, even while `read_thread` still works.
6. After approximately 90 seconds, ask Voice to create a second harmless projectless task.
7. Observe `Something went wrong while running this tool.`
8. Ask Voice to list tasks. Cached rows may still be returned, but the same live host is marked `thread_list_unavailable`.
9. Try reading, messaging, or forking the first child task. Those live operations fail as well.
10. Use **New Task** directly in the desktop UI. Observe that task creation and execution still work normally.
The failure has persisted across multiple complete desktop-app restarts. A restart may temporarily help individual missing-handler failures reported by other users, but it has not provided a durable recovery here.
### Expected behavior
- Every task tool advertised to a Voice turn should have a callable handler for that turn.
- Creating or completing a child task must not invalidate the parent Voice conversation's route to the host.
- Dynamic task-tool requests should have one authoritative responder.
- A non-owning subscriber's missing-handler response must not override a valid response from the handler-owning subscriber.
- Replaying or retrying a side-effecting task operation must not create duplicate tasks.
- If the live host is unavailable, the tool should return the underlying routing error rather than a generic failure while simultaneously displaying cached host metadata.
### Actual behavior
- A first delegated task succeeds.
- `wait_threads` is advertised but immediately has no registered handler.
- `read_thread` continues to work through child completion.
- Around 92 seconds later, create/read/message/fork operations fail.
- Cached task and project metadata remain visible.
- The same host is then marked `thread_list_unavailable`.
- Direct desktop task creation remains operational.
### Sanitized timeline
Times are UTC. All task, turn, request, connection, and host identifiers have been removed.
| Time | Observation |
|---|---|
| `19:31:59` | Realtime Voice calls `create_thread` for a harmless projectless task. |
| `19:32:01` | Creation succeeds and returns one child task. |
| `19:32:12` | `wait_threads` returns `No handler registered`. |
| `19:32:18` | `read_thread` succeeds. |
| `19:32:31` | A second `read_thread` succeeds. |
| `19:32:37` | The child reports completion to the Voice parent. |
| `19:32:39` | The child turn completes. |
| `19:32:41` | `read_thread` succeeds after child completion. |
| `19:33:58` | Project discovery still returns the current host and saved project metadata. |
| `19:34:12` | The next `create_thread` returns the generic tool error. |
| `19:34:22` | A retry fails identically. |
| `19:34:30` | A different projectless creation attempt fails identically. |
| `19:34:34` | Task listing returns cached rows but marks the current host `thread_list_unavailable`. |
| `19:34:44` | `send_message_to_thread` fails. |
| Later | Further create, read, message, fork, and terminal-read operations fail. |
This timing rules out immediate child-completion teardown: a live read succeeded after completion. The transition to generic failures occurred approximately 92 seconds after completion, which may indicate a route lease, inactivity timeout, reconnect, or response-delivery problem. That mechanism is an inference, not a confirmed root cause.
### Local controls and diagnostic evidence
The following remained healthy while Voice task operations failed:
- Direct desktop **New Task** creation and execution.
- The local Codex app-server and bundled Code Mode host processes.
- Local Unix-socket connections.
- Local `thread/read`, `thread/resume`, `thread/list`, `thread/turns/list`, and `turn/start` responses in desktop logs.
- Local task-catalog database integrity check.
- Authentication status calls.
- A single primary desktop application process, with no duplicate full app instance.
Projectless tasks fail, which rules out a particular repository, worktree, project configuration, or task prompt as the cause.
### Corroborating local tool-bridge evidence
A separate local-only scheduled workflow calls the agent-facing task-list tool with `hostId=local`. On multiple runs, that agent-facing call failed to return for more than 90 seconds and was terminated. During one of those incidents, the desktop log recorded the underlying local app-server `thread/list` request completing successfully with no error in approximately 2 ms. Later retries recovered and returned normal results.
This independently suggests that at least some failures occur above the canonical local task catalog and app-server, in tool routing, handler dispatch, or response delivery. This is corroborating evidence only. The local-host hang and the Realtime Voice `slingshot` failure are not proven to share one root cause.
### Related public reports
- [#35894: dynamic tool request is broadcast to all task subscribers and first response wins](https://github.com/openai/codex/issues/35894)
- [#36013: tool discovery advertises `read_thread`, but invocation has no registered handler](https://github.com/openai/codex/issues/36013)
- [#36257: one `create_thread` operation during Remote Realtime Voice produced seven persisted tasks](https://github.com/openai/codex/issues/36257)
- [#31119: task creation reports a handler error while a child task may still exist](https://github.com/openai/codex/issues/31119)
- [#28080: desktop task tools intermittently lose handlers](https://github.com/openai/codex/issues/28080)
The reports on desktop `26.721` and bundled CLI `0.146.0-alpha.3.1` show that this failure family predates desktop `26.727`. The current update is temporally correlated with this reproduction but is unlikely to be the sole origin of the underlying defect.
### Inference, not confirmed: source-level correlation
The following is an inference based on public source code and related reports. I do not have access to OpenAI's internal Voice or host-routing telemetry. The source-reviewed behavior in #35894 is a strong fit for the missing-handler portion of this incident:
- A task-scoped dynamic tool request is sent to every subscribed connection using the same request ID.
- The pending callback is keyed by request ID.
- The first response or error resolves the callback without validating that it came from the handler-owning connection.
- A non-owning subscriber can therefore return `No handler registered` before the authoritative handler succeeds.
- Retrying after a false failure can duplicate a side effect such as task creation.
The relevant outgoing-request implementation is present in [Codex 0.146](https://github.com/openai/codex/blob/rust-v0.146.0/codex-rs/app-server/src/outgoing_message.rs#L287-L350). A local comparison of official tags found that the relevant file is byte-identical in `0.145.0`, `0.146.0-alpha.3.1`, `0.146.0-alpha.9.2`, and stable `0.146.0`.
This likely explains one causal component, but it does not by itself prove why the live Voice host route becomes unavailable after roughly 90 seconds. There may be two interacting defects:
1. Tool discovery or per-turn handler registration advertises tools that the active responder cannot execute.
2. The Voice/remote host route later expires, disconnects, or loses response delivery while the local app-server remains healthy.
### Suggested engineering investigation
- Trace Voice host registration, route ownership, and lease/reconnect events across the 90-second transition.
- Correlate each dynamic tool request with every subscribed connection and record which connection returned the winning response.
- Require exactly one authoritative handler-owning responder for a dynamic tool request.
- Store and validate the expected connection ID when resolving responses or errors.
- Make dynamic tool discovery and handler registration atomic across task resume, renderer rehydration, context compaction, and Voice reconnection.
- Ensure child completion cannot release or invalidate a route shared with the parent Voice conversation.
- Add idempotency protection for `create_thread` and other side-effecting retries.
- Preserve the underlying host-routing or handler-registration error instead of returning only `Something went wrong`.
- Add an integration test with Realtime Voice, desktop primary UI, Voice/avatar overlay, Remote, and the local app-server subscribed concurrently.
### Additional information available privately
The reporter can provide the following privately through an OpenAI-controlled support or in-app feedback channel:
- Parent and child task identifiers.
- Sanitized request and turn identifiers.
- Sanitized host and connection identifiers.
- Narrow desktop-log excerpts surrounding the failure window.
- The parent Voice rollout with prompt content and local paths removed.
Raw logs should not be attached to a public GitHub issue because they contain local paths, task identifiers, project metadata, and potentially private prompt content.
## Privacy review
This public draft intentionally excludes:
- Personal name, username, email address, account identifier, and hostname.
- Geographic location and local timezone.
- Home-directory and application-support paths.
- Employer, repository, worktree, project, and external-service names.
- Real parent, child, turn, request, connection, and host identifiers.
- Prompt contents other than the generic description of a harmless projectless control task.
- Raw desktop logs, rollout files, database paths, authentication data, tokens, and credentials.
The exact app versions, generic hardware platform, UTC timestamps, public issue links, error strings, and sanitized durations are retained because they are directly relevant to reproduction and diagnosis.