[Windows][26.803.5235.0] Empty provisional realtime voice thread emits null realtimeSessionId and never reaches connected
What version of the Codex App are you using (From “About Codex” dialog)?
Version 26.803.41515
What subscription do you have?
Plus Subscription ($20)
What platform is your computer?
Microsoft Windows NT 10.0.29639.0 x64
What issue are you seeing?
Starting a new realtime voice chat from an empty Codex Desktop task consistently times out on Windows.
The app-server accepts thread/realtime/start, but the subsequent realtime-started event is logged with a null session ID:
realtime_session_started realtimeSessionId=null
The Desktop renderer cannot transition the pending voice launch to the connected state because its pending-session matching logic requires a non-null realtimeSessionId. The upstream WebRTC call-create request succeeds with HTTP 201, so this is not simply an upstream call-creation or quota failure.
The failure occurs when voice is started before the provisional task has received its first user message. The relevant sequence is:
thread/realtime/start accepted
thread/read attempted while the provisional thread is still empty
thread/read fails because includeTurns is unavailable before the first user message
realtime_session_started realtimeSessionId=null
Voice chat took too long to start
thread/realtime/stop
Representative sanitized logs:
2026-08-08T16:27:52.179Z info [AppServerConnection] realtime_session_started hostId=local realtimeSessionId=null threadId=019fe233-9a48-7b52-9ec6-051a4f3fa36c
2026-08-08T16:27:54.565Z info [AppServerConnection] realtime_session_started hostId=local realtimeSessionId=null threadId=019fe233-c952-7583-a84f-4eda142e87f5
Another attempt:
16:27:53.218 thread/realtime/start durationMs=119 <- accepted
16:27:53.457 thread/read durationMs=332
16:27:54.140 thread/read durationMs=227
16:27:54.565 realtime_session_started realtimeSessionId=null
16:27:58.145 Voice chat took too long to start
16:27:58.207 thread/realtime/stop durationMs=43
The associated empty-thread read failure is:
thread <redacted-thread-id> is not materialized yet;
includeTurns is unavailable before first user message
The UI error is:
Voice chat took too long to start
DeviceCheck also repeatedly reports:
DeviceCheck attestation unavailable errorCode=1
I have not assumed that the DeviceCheck error is benign. Its exact surrounding local log context still needs to be correlated with the realtime attempt.
Relevant provisional thread IDs from the failed attempts are:
019fe233-9a48-7b52-9ec6-051a4f3fa36c
019fe233-c952-7583-a84f-4eda142e87f5
No upstream realtime session ID was returned; the observed value was null.
There was no user prompt or first user message before the voice button was clicked. Token-limit and context-window usage are not applicable to the failure as observed: the launch fails during realtime startup before a normal model turn begins, and the supplied logs contain no token-usage or context-window measurement.
What steps can reproduce the bug?
Windows 11 Pro, build 10.0.29639
Codex Desktop MSIX package:
OpenAI.Codex_26.803.5235.0_x64__2p2nqsd0c76g0
Bundled/pinned app-server path, with the username redacted:
C:\Users\<USER>\AppData\Local\OpenAI\Codex\bin\cfac6bda2d141e07\codex.exe
Reported app-server version:
codex-cli 0.147.0-alpha.6.5
Reported alpha source commit: 618b8e9
CODEX_HOME:
C:\Users\<USER>\.codex
Realtime transport: WebRTC
No WebSocket fallback is available in the installed runtime.
Reproduction:
Fully exit and reopen Codex Desktop.
Open a new empty task.
Do not send a user message.
Click the real Desktop voice/start-new-voice-chat button.
Observe the Desktop and app-server logs.
The request is accepted, an empty provisional-thread read occurs, and the started event is logged with realtimeSessionId=null.
The voice overlay eventually reports Voice chat took too long to start.
A protocol-level reproduction should use a real browser-generated WebRTC SDP offer rather than a hand-written SDP string:
const pc = new RTCPeerConnection();
const audioStream =
await navigator.mediaDevices.getUserMedia({ audio: true });
pc.addTrack(audioStream.getAudioTracks()[0], audioStream);
pc.createDataChannel("oai-events");
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
// Send this JSON-RPC request through the authenticated app-server
// connection. Replace <thread-id> and the SDP placeholder.
const request = {
jsonrpc: "2.0",
id: 40,
method: "thread/realtime/start",
params: {
threadId: "<thread-id>",
outputModality: "audio",
realtimeSessionId: null,
transport: {
type: "webrtc",
sdp: pc.localDescription.sdp
}
}
};
The realtimeSessionId: null value in the protocol snippet represents the default-ID path described by the public app-server API. The actual Desktop raw JSON-RPC request was not captured in this report, so I am not claiming that the Desktop request definitely contained that field/value; confirming the raw request and raw notification is part of the requested investigation.
The expected server-side sequence should include:
thread/realtime/start -> {}
thread/realtime/started -> {
threadId: "...",
realtimeSessionId: "<non-null-id>"
}
thread/realtime/sdp -> {
threadId: "...",
sdp: "..."
}
The observed sequence instead contains:
thread/realtime/started -> {
threadId: "...",
realtimeSessionId: null
}
The proxy log recorded HTTP 201 for the realtime call-create request. That confirms that upstream call creation can succeed, but it does not demonstrate that Desktop receives a valid realtime session ID or reaches the connected state.
What is the expected behavior?
Starting voice from an empty task should not cause Desktop to hydrate an unmaterialized provisional thread with an invalid includeTurns read.
The provisional voice task should either materialize correctly before hydration or proceed with a valid realtime session identifier.
The real Desktop voice launch should reach this trajectory:
voice-button click
-> thread/realtime/start accepted
-> raw thread/realtime/started notification
with a non-null realtimeSessionId
-> realtimeSessionId matches the pending voice session
-> thread/realtime/sdp
-> WebRTC connected state
-> no "Voice chat took too long to start" error
The realtimeSessionId should be non-null even if it is derived from the Codex thread ID. It should not be confused with the separate rtc_... WebRTC call ID used for sideband joining.
Additional information
Public-source discrepancy
The public rust-v0.147.0 source appears to produce a non-null default session ID:
build_realtime_session_config sets the session ID to the request’s realtimeSessionId, or falls back to the thread ID.
prepare_realtime_start clones that value into requested_realtime_session_id.
The started event emits that requested value as realtime_session_id.
Relevant official source:
realtime_conversation.rs
realtime_call.rs
Official app-server realtime documentation
The WebRTC call implementation separately removes the session JSON object’s id before creating the call and extracts an rtc_... call ID from the response Location header. That rtc_... call ID is used for sideband joining and is not the same field as the app-server realtimeSessionId.
A comparison of the relevant source ranges between rust-v0.147.0-alpha.6.5 and rust-v0.147.0 did not show a relevant change in the realtime-session-ID path. The stable release notes also do not identify an explicit fix for this null-ID/provisional-thread failure:
Stable 0.147.0 release notes
Alpha 0.147.0-alpha.6.5 release
Exact public matching issue #35252
Stable has not been substituted for the Desktop-pinned runtime on this machine, so I am not claiming that stable fixes the installed behavior.
Config investigation
The public configuration parser recognizes these experimental keys:
experimental_realtime_ws_base_url = "..."
experimental_realtime_webrtc_call_base_url = "..."
Official parser source:
config_toml.rs
The source documents these as transport endpoint overrides:
experimental_realtime_ws_base_url changes the realtime WebSocket endpoint.
experimental_realtime_webrtc_call_base_url changes the WebRTC call-creation endpoint.
Neither key supplies or repairs the per-request realtimeSessionId. No supported global config or environment key was found that forces a non-null realtime session ID.
Commenting out the local openai_base_url setting did not change the failure. The upstream call-create request still succeeded with HTTP 201.
No config file was changed during this investigation.
DeviceCheck / attestation
The repeated Desktop message is:
DeviceCheck attestation unavailable errorCode=1
The official app-server documentation defines status code 1 in its own attestation envelope as a timeout:
1 = timeout
2 = request failed
3 = request canceled
4 = malformed response
See the official attestation-generation documentation.
However, it has not yet been proven that the Desktop DeviceCheck errorCode=1 line is reporting that same app-server envelope. Please confirm whether this is:
the app-server attestation status s=1;
a Desktop-specific DeviceCheck error code; or
another wrapper-level error.
The DeviceCheck error should not be assumed benign from recurrence alone. It is also not yet proven to be the cause of the null realtime session ID.
Evidence still needed from maintainers
Please confirm:
Whether the empty provisional-thread path is expected to emit thread/realtime/started with a non-null session ID.
Whether the raw JSON-RPC thread/realtime/start request contains realtimeSessionId, and what value it contains.
Whether the raw JSON-RPC thread/realtime/started notification contains null or whether the value is lost inside Desktop’s notification mapping/logging layer.
The exact Desktop/app-server release or commit that fixed issue #35252.
Whether stable rust-v0.147.0 is supported and hash-compatible with Desktop package 26.803.5235.0.
Whether the Desktop renderer should fall back to the pending voice session ID when the started notification is null, or whether app-server must always emit the ID.
Whether DeviceCheck attestation unavailable errorCode=1 maps to the documented app-server attestation status 1 = timeout.
Whether an attestation failure can affect the realtime-started notification independently of the successful HTTP 201 call-create response.
The decisive falsifying evidence would be either:
a raw JSON-RPC trace showing a valid non-null realtimeSessionId that Desktop later logs as null, which would implicate Desktop’s mapping/logging layer; or
a clean real voice-button run on the same Desktop package/runtime that reaches connected with a matching non-null realtimeSessionId, which would disprove persistence of the reported failure.
5 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
I can confirm that this still reproduces on Windows in Codex Desktop 26.803.10989.0.
Observed on August 11, 2026:
thread/realtime/start.thread/readthen fails because the task is not materialized yet andincludeTurnsis unavailable before the first user message.realtime_session_startedis logged withrealtimeSessionId=null, followed by stop/cleanup errors.This does not appear to be a microphone, audio-device, account, or basic transport problem:
There is an additional routing symptom in 26.803.10989.0:
After Voice launch from a new empty task fails, the configured Voice shortcut (Alt+D) consistently resumes the same older voice-originated task, even when another task is visibly selected. The selected task remains on screen, but the blue active-Voice indicator moves to the older task. The logs confirm that the shortcut sends
thread/realtime/startfor that older task, and that request succeeds.This suggests that the provisional-task failure leaves behind, or falls back to, a stale “last valid Voice task” target. The timeout/null-session bug therefore appears to remain present in the current build, with an additional wrong-task routing/fallback symptom.
First observed locally in 26.803.5235.0 on August 7–8, and still present after updating to 26.803.10989.0 on August 11. The issue predates the ChatGPT service incident reported on August 11.
Update: the same failure reproduces on a newer Windows Codex Desktop package.
Environment
OpenAI.Codex_26.810.6296.026.810.508560.148.0-alpha.926200Reproduction and actual behavior
Sanitized log sequence from the same attempt:
This reproduces the core sequence reported in this issue, now on
26.810.6296.0/ app-server0.148.0-alpha.9. The session ID remains null and the provisional-thread cleanup/resume path is still broken.Additional information
During the same failure, the Codex UI/desktop pointer became severely laggy. Switching to a wired mouse did not change the symptom, while Ctrl+Alt+Delete remained responsive. Restarting Codex restored normal pointer behavior. This may be a related overlay/window-lifecycle symptom rather than a hardware problem.
No usernames, task IDs, local paths, conversation contents, raw logs, credentials, or tokens are included.
Additional sanitized reproduction from another Windows installation using official ChatGPT authentication:
OpenAI.Codex_26.803.5235.0_x6426.803.41515base_url.Observed sanitized behavior:
Voice chat took too long to startbefore anythread/realtime/startentry appeared.thread/startrequests within approximately 10 ms; both provisional tasks were subsequently discarded, and neither reachedthread/realtime/start.This looks related to the empty/provisional Voice task lifecycle and/or client-side launch state, even when the application is already warm and an existing task is selected. Please confirm whether the fix for the null
realtimeSessionIdpath in this issue has landed in a public Desktop build. I can provide further sanitized timing traces if useful.Follow-up with a newer reproduction from the same Windows machine after the previous report:
26.814.419570.148.0The read-only local log window around the attempt shows:
thread/startbegan at approximately 23:00:38 withdynamic_tool_count=21.thread/startrequest was cancelled at approximately 23:01:41.thread/realtime/startand norealtime_session_startedevent appeared within that request window.This reproduces the failure after warm-up and from an existing task, and places the failure before Realtime/WebRTC/ICE/microphone setup. It appears to be a broader provisional Voice thread/MCP lifecycle cancellation than a simple cold-start delay. Please let me know whether a public Desktop build contains a fix for this path.