Realtime Voice loses Codex task-tool handlers and live host route after successful delegation

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

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:

Something went wrong while running this tool.

Two advertised tools returned:

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:

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

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. 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.

View original on GitHub ↗

6 Comments

github-actions[bot] contributor · 27 days ago

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

  • #35894
  • #36013

Powered by Codex Action

JanSay · 24 days ago

I am seeing a closely related failure in the macOS desktop app through Realtime Voice. A previous conversation remains visible in the task list, but reading the thread and sending a follow-up both fail with a generic error. The task list simultaneously reports the host as unavailable. This makes it impossible to tell whether a delegated test task is still running, has completed, or needs intervention, even though a Codex worker process remains active for the project. The most damaging part is the loss of observability and control after delegation: the work may continue, but the user cannot inspect or resume it. Please improve the recovery path and surface a clear, actionable status instead of a generic failure.

mickn · 16 days ago

I can corroborate this failure on a later Desktop build.

Environment

  • ChatGPT/Codex desktop: 26.803.61601 (bundle build 6396)
  • Bundled app-server user agent: Codex Desktop/0.147.0-alpha.6.5
  • Standalone Codex CLI: 0.147.0
  • macOS on Apple Silicon

Sanitized reproduction (2026-08-11, UTC)

  • 20:01:20: Realtime Voice called list_threads({limit:100}).
  • The call returned 50 thread rows in about 0.6 s, but simultaneously reported the same-machine slingshot: route as thread_list_unavailable.
  • A repeated list behaved identically.
  • 20:02:09: Voice listed threads and attempted to read the first active thread using the returned host route. The read returned Something went wrong while running this tool.
  • 20:11:13: An ordinary text Codex thread called list_threads({limit:50}); it timed out after 30 s.
  • A fresh text thread later reproduced unbounded waits:
  • list_threads({limit:20}): no response after more than 57 s
  • list_threads({limit:5}), list_projects(), and read_thread(...): no response after more than 21 s each
  • explicitly forcing hostId: "local" did not bypass the hang

Control results

During the same app session:

  • A fresh instance of the exact app-server binary bundled with Desktop completed ordinary thread/list (limit 20, normal scan-and-repair path) in 352 ms.
  • Direct thread/read for the thread Voice could not read completed in 192 ms.
  • The local state database passed PRAGMA quick_check; its indexed top-20 query completed in 0.01 s.
  • The main Desktop app-server also remained responsive: its log shows thread/turns/list routed successfully in 107 ms with errorCode=null while the agent-facing thread-management call was affected.

This strongly localizes the failure above the canonical thread store and app-server, in the Desktop/Voice codex_app handler, host router, or response-delivery path. It also makes accumulated history unlikely to be the proximate cause of these particular hangs.

One potentially relevant correlation: Electron recorded net::ERR_NETWORK_CHANGED at 20:09:57. That event occurred about eight minutes after Voice first returned thread_list_unavailable, so it cannot explain the initial route degradation. It may, however, be useful to correlate with the later transition from fast cached/partial results to calls that never returned.

No restart or configuration change was performed before capture. Exact operational identifiers and narrow raw-log excerpts are available privately to OpenAI, but are intentionally omitted here.

radwagusa · 16 days ago

Additional corroboration on the current macOS Desktop build, specifically through iOS Remote + Realtime Voice.

Environment

  • ChatGPT/Codex desktop: 26.803.61601 (bundle build 6396)
  • Bundled Codex CLI: 0.147.0-alpha.6.5
  • macOS on Apple Silicon
  • iOS ChatGPT current as of 2026-08-11
  • Same account/workspace; Mac awake, online, and powered

Same-session transition from healthy to unavailable

Times are UTC; identifiers and prompt content are omitted.

| Time | Directly recorded result |
|---|---|
| 22:54:57 | Voice list_threads succeeded with unavailableHosts: []. |
| 22:55:24 | Voice read_thread succeeded for an existing completed thread. |
| 22:56:11 and 22:56:16 | Valid read_thread calls for another existing thread returned Something went wrong while running this tool. |
| 22:56:22 | wait_threads returned the same generic failure. |
| 22:56:25 and 22:56:37 | list_threads returned a cached matching row while also reporting the same live host as thread_list_unavailable. |
| 22:56:40 | Another valid read_thread failed generically. |
| 22:57:42 | A valid projectless create_thread returned the generic tool error. |

This sequence comes from persisted tool-call records, not from the Voice model's interpretation. It shows successful and failed live host operations in the same Voice session roughly one minute apart, which rules out a static capability or workspace-permission denial.

Transport evidence

A desktop log from the same incident family records:

  • 22:25:59.441Z: remote control websocket writer was stopped
  • 22:26:11.191Z: connection-failed surfaced while the connection manager still reported state=connected
  • 22:26:11.215Z: socket write failed with EPIPE

That connected-state mismatch appears highly relevant: the client can continue presenting the host as connected while its live Remote Control writer is gone. Cached thread rows/navigation can remain available, but live read/create/wait/message operations fail or hang.

Later, two fresh non-Voice thread-list probes timed out after 12 seconds even after parallel diagnostic workers were stopped. The desktop application and app-server remained alive and ordinary network access remained healthy.

Recovery attempts

The failure was not durably repaired by:

  • disconnect/reconnect from the phone;
  • fresh Voice chats;
  • desktop quit/relaunch;
  • full Mac reboot.

A full host unpair/re-pair has not yet been attempted because the user is away from the host Mac.

Please correlate Remote host registration/route ownership with the WebSocket-writer stop and ensure state=connected is invalidated when the writer exits. Exact session/host identifiers and narrow redacted log excerpts are available privately through an OpenAI-controlled feedback channel.

radwagusa · 16 days ago

Correction and higher-confidence isolation from follow-up forensics:

Correction to my preceding comment

The 22:25:59Z WebSocket-writer stop and 22:26:11Z EPIPE should not be treated as the causal event.

  • The Remote state machine immediately transitioned from Connected to Connecting, refreshed its token, and reconnected at 22:26:01Z with its subscription cursor present.
  • Desktop began intentionally stopping the old local app-server sidecar at 22:26:09Z.
  • The EPIPE followed that shutdown and is therefore teardown collateral.
  • The Voice thread-tool failure was already present by 22:10Z, approximately 15 minutes before that writer event.

Stronger same-session evidence

The previously posted same-session transition remains valid: Voice list/read calls succeeded at 22:54:57Z and 22:55:24Z, then read/wait/list/create failed beginning 22:56:11Z. During that transition there was no VPN/tunnel/path change, Wi-Fi loss, sleep/wake, DNS failure, Remote WebSocket disconnect, or general network error. Voice input and unrelated tool calls continued.

A later Voice session at 23:25Z again returned cached thread rows plus thread_list_unavailable, while live read_thread failed generically.

Local-versus-Remote A/B control

At 23:39:55Z, a separate instance of the exact app-server binary bundled with Desktop was initialized against the same local Codex state. It completed:

  • three thread/read calls in 5, 7, and 8 ms;
  • three thread/list calls in 24, 25, and 25 ms;
  • all six successfully, in a 25 ms batch;
  • clean exit, no stderr, and no thread mutation.

The active state database also passes PRAGMA quick_check, contains one enabled Remote enrollment matching the current installation, and only one live Desktop app-server process was present. This rules down local thread storage, the canonical app-server methods, an active VPN, and a duplicate local process.

Historical logs for the same persisted Remote enrollment contain an HTTP 409 Remote app server already online after a prior local process had stopped. That proves a relay lease/ownership record can outlive a local process, although it does not prove that a ghost owner is active in this incident.

Revised diagnosis

The confirmed failure boundary is the Remote/Voice host-RPC bridge or its per-capability handler mapping: cached discovery can identify the host while live thread callbacks to that host become unreachable. A stale/competing enrollment route, lease ownership, or subscriber/handler-routing defect is the best-fit mechanism, but the exact server-side defect remains an inference.

Please inspect:

  1. enrollment and route ownership for hosts returning thread_list_unavailable;
  2. cached host discovery versus the live thread callback route;
  3. duplicate/stale subscribers and dynamic-tool response ownership;
  4. why the Remote UI can remain connected while the thread capability route is unavailable;
  5. whether support can invalidate the affected enrollment/lease server-side.

A full Mac-side unpair, quit, lease-expiry wait, and fresh QR enrollment is the most targeted client reset, but it is not a confirmed fix.

dhbrand · 14 days ago

Additional corroboration from ordinary Codex text tasks and a scheduled task audit on the same macOS Desktop release (26.803.61601).

Four-day persisted-call review

After excluding immediate schema-validation failures and stale-project-ID errors, I found 40 opaque task-tool failures returning only:

Something went wrong while running this tool.

Affected operations:

| Operation | Opaque failures |
|---|---:|
| read_thread | 14 |
| create_thread | 8 |
| set_thread_title | 8 |
| send_message_to_thread | 8 |
| list_threads | 1 |
| set_thread_archived | 1 |

The failures include local, remote, and implicit-host calls. Because set_thread_title for the calling task itself fails in the same clusters, this does not appear isolated to one target thread, one remote host, or one task operation.

Scheduled-task signature

On three consecutive daily scheduled runs, a valid list_threads({limit:50}) call never returned a task result. The wrapper remained pending and had to be terminated after bounded waits. The identical call later succeeded from an ordinary manual turn.

A current control ran the same exact list_threads({limit:50}) call ten times sequentially:

  • 10/10 succeeded
  • latency range: 0.98-1.80 s
  • each returned 50 rows
  • no unavailable hosts or sources were reported

This rules down the limit, task-history size, machine sleep, and a permanent local-store failure. It fits an intermittent handler/router/response-delivery failure, with scheduled execution providing a repeatable context in which the bridge can be unready.

Observability gap

Desktop logs preserve precise validation errors such as invalid argument limits, but the opaque failures expose no underlying exception. The persisted task record contains only the generic message. Preserving a structured error code plus route/handler ownership information would make this diagnosable without private raw logs.

All counts above come from persisted tool-call records. Local paths, task IDs, project identifiers, prompts, and account data are intentionally omitted.